Ich versuche Springboot, HSQL und Hibernate zusammen zu verwenden, um einige ziemlich langweilige Daten zu erhalten. Das Problem, das ich in laufen lasse, ist, dass Hibernate meine Tabellen nicht in der Lage scheint korrekt zu verweisen, die folgende Ausnahme werfen:Springboot, Hibernate4 und HSQL Zugreifen auf Schema falsch?
ERROR [main] (SpringApplication.java:826) - Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'strangerEntityManagerFactory' defined in class path resource [com/healz/stranger/config/profiles/GenericSqlConfig.class]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Missing column: user_USER_ID in PUBLIC.STRANGER.PROTECTED_PROPERTIES
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
...
Anfang war ich HSQL-Standardschemanamen, PUBLIC und bemerkte mit, dass die Ausnahme ausgelöst bekommen war, dass Die Anwendung konnte PUBLIC.PUBLIC.PROTECTED_PROPERTIES nicht finden. Das sieht sehr verdächtig aus - warum gibt es hier eine "extra Schicht" von PUBLIC? Es sieht definitiv nicht richtig aus. Der Code, der die EntityManagerFactory Setup funktioniert wie folgt aussieht:
@Log4j
@Configuration
@EnableAspectJAutoProxy
@ComponentScan (basePackages = {"com.healz.stranger.data"})
@EnableJpaRepositories (
entityManagerFactoryRef="strangerEntityManagerFactory",
transactionManagerRef="txManager",
basePackages={"com.healz.stranger.data.model"}
)
@EntityScan (basePackages={
"com.healz.stranger.data.model"
})
@Import ({HsqlConfig.class, DevMySqlConfig.class, ProdMySqlConfig.class})
public class GenericSqlConfig {
@Configuration
@EnableTransactionManagement(order = Ordered.HIGHEST_PRECEDENCE)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
protected static class TransactionManagementConfigurer {
// ignore annoying bean auto-proxy failure messages
}
@Bean
public static PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() throws Exception {
return new PersistenceAnnotationBeanPostProcessor();
}
@Bean
public JpaDialect jpaDialect() {
return new HibernateJpaDialect();
}
@Autowired
@Qualifier("hibernateProperties")
private Properties hibernateProperties;
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;
@Bean (name="strangerEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean strangerEntityManagerFactory(
final @Qualifier("hibernateProperties") Properties props,
final JpaDialect jpaDialect) {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
emf.setPackagesToScan("com.healz.stranger.data");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
emf.setJpaProperties(hibernateProperties);
emf.setJpaDialect(jpaDialect);
emf.setPersistenceUnitName("strangerEntityManagerFactory");
return emf;
}
@Bean (name="sessionFactory")
public SessionFactory configureSessionFactory(LocalContainerEntityManagerFactoryBean emf) {
SessionFactory sessionFactory = emf.getObject().unwrap(SessionFactory.class);
return sessionFactory;
}
/**
* Helper method to get properties from a path.
* @param path
* @return
*/
@SneakyThrows (IOException.class)
public static Properties getHibernatePropertiesList(final String path) {
Properties props = new Properties();
Resource resource = new ClassPathResource(path);
InputStream is = resource.getInputStream();
props.load(is);
return props;
}
@Bean (name="txManager")
@Autowired
public PlatformTransactionManager getTransactionManager(LocalContainerEntityManagerFactoryBean lcemfb, JpaDialect jpaDialect) {
EntityManagerFactory emf = null;
emf = lcemfb.getObject();
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(emf);
jpaTransactionManager.setJpaDialect(jpaDialect);
return jpaTransactionManager;
}
}
Die HSQL Config wie folgt aussieht:
@Configuration
@Profile ("hsql")
public class HsqlConfig {
@Bean(name = "dataSource")
public DataSource initDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:env/dbcache/hsql-schema.sql")
.addScript("classpath:env/dbcache/hsql-data.sql");
builder.setName("stranger");
builder.setScriptEncoding("UTF-8");
return builder.build();
}
@Bean(name = "hibernateProperties")
public Properties getHibernateProperties() {
Properties props = new Properties();
props.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
props.put("hibernate.hbm2ddl.auto", "validate"); // using auto and ignoring the hsql scripts "works", but isn't correct
props.put("hibernate.default_schema", "stranger");
props.put("hibernate.current_session_context_class", "org.hibernate.context.internal.ThreadLocalSessionContext");
return props;
}
}
Die andere noticably Seltsame daran ist, dass Hibernate Suche eine Spalte zu sein scheint mit der Name user_USER_ID anstelle von USER_ID, und ich bin mir nicht sicher, warum das auch passiert. Ich bezweifle, dass dies alles durch einen Mapping-Fehler verursacht wurde, da ähnlicher Code mit einer anders konfigurierten EntityMappingFactory zu funktionieren scheint, aber ich möchte diese Möglichkeit nicht ausschließen. Der Code für diese sieht wie folgt aus:
@Entity (name="properties")
@Table (name="PROTECTED_PROPERTIES")
public class DbProtectedProperties extends AbstractModel<DbProtectedPropertiesId> implements Serializable {
private static final long serialVersionUID = 1L;
public void setId(DbProtectedPropertiesId id) {
super.id = id;
}
@EmbeddedId
public DbProtectedPropertiesId getId() {
if (super.id == null) {
super.id = new DbProtectedPropertiesId();
}
return super.id;
}
@Column (name="PROPERTY_VALUE", length=4096, nullable=false)
public String getPropertyValue() {
return propertyValue;
}
@Setter
private String propertyValue;
}
und die ID-Klasse:
@EqualsAndHashCode (of={ "user", "propertyName" })
@ToString
public class DbProtectedPropertiesId implements Serializable {
private static final long serialVersionUID = 1L;
@Setter
private DbUsers user;
@Setter
private String propertyName;
@ManyToOne (optional=false, fetch=FetchType.EAGER)
@PrimaryKeyJoinColumn (name="USER_ID")
public DbUsers getUser() {
return user;
}
@Column (name="PROPERTY_NAME", length=2048, nullable=false, insertable=false, updatable=false)
public String getPropertyName() {
return propertyName;
}
}
Gibt es einen Grund, warum Sie versuchen, den Spring-Boot nicht zu verwenden? Sie versuchen sehr hart, um es zu umgehen ... Was noch schlimmer ist, ist, dass Ihre Konfiguration Dinge wie Transaktionsmanagement bricht. –
Können Sie diesen Kommentar erweitern? Es ist mir nicht klar, was du damit meinst. Spring Boot macht eine Menge automatische Konfiguration und es ist mir nicht ganz klar, was automatisch ausgeführt wird. Ich habe bereits festgestellt, dass einige dieser Objekte automatisch erstellt und konfiguriert wurden. Ist ein TransactionManager auch eingerichtet und konfiguriert? – xtro
Grundsätzlich ist alles, was Sie haben, automatisch konfiguriert. Das einzige, was nicht ist, ist die 'SessionFactory', aber warum brauchen Sie das, wenn Sie den' EntityManager' verwenden können? Ich würde alles entfernen, erstellen Sie eine globale 'application.properties' und spezifische' application- .properties' und beginnen Sie damit. –