我在Spring中使用HSQL
数据库有一些非确定性行为。有时,sequence
会生成两次,DataSource
初始化会因此失败。
奇怪的是,如果它失败了,它总是来自试图读取不存在的数据库条目的测试。其他读取现有条目的测试都不会失败。
我真的不明白我做错了什么以及为什么会这样。
HSQLDB
版本为2.3.2
更新 我已经完全删除了序列,现在我再次,有时会得到表格凭证被创建两次的错误。
这是我的配置:
@EnableJpaRepositories
@EnableTransactionManagement
@Configuration
@Profile("test")
public class TestDatabaseConfig {
@Bean
@Primary
public EntityManagerFactory entityManagerFactory() throws ClassNotFoundException {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan(ENTITIES_PACKAGE);
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
@Primary
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().addDefaultScripts()
.setType(EmbeddedDatabaseType.HSQL)
.build();
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) throws ClassNotFoundException {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
schema.sql:
CREATE SEQUENCE voucher_id_seq AS INTEGER START WITH 100 INCREMENT BY 1;
CREATE TABLE voucher (id INTEGER, code VARCHAR(64) NOT NULL UNIQUE, type VARCHAR(64) NOT NULL, state VARCHAR(64) NOT NULL, class_name VARCHAR(64), serial VARCHAR(64), consumption_user VARCHAR(255), creation_date TIMESTAMP DEFAULT current_timestamp, consumption_date TIMESTAMP, expiry_date TIMESTAMP)
data.sql:
-- VALID
INSERT INTO voucher (id, code, type, state, serial ) VALUES (1,'success', '1', 'E', 'serial: 123');
--ALREADY CONSUMED
INSERT INTO voucher (id, code, type, state) VALUES (2,'used', '1', 'U');
-- DATE EXPIRED
INSERT INTO voucher (id, code, type, state, expiry_date) VALUES (3,'expired', '1', 'E', DATE '2014-12-12');
错误跟踪,在顶部你可以看到有时生成两次序列:
引起:org.springframework.beans.BeanInstantiationException:无法实例化[javax.sql.DataSource]:工厂方法' dataSource'抛出异常;嵌套异常是org.springframework.jdbc.datasource.init.ScriptStatementFailedException:无法在资源类路径资源[schema.sql]的第1行执行SQL脚本语句:CREATE SEQUENCE voucher_id_seq AS INTEGER START WITH 100 INCREMENT BY 1;嵌套异常是java.sql.SQLSyntaxErrorException:对象名已存在:语句中的VOUCHER_ID_SEQ [CREATE SEQUENCE voucher_id_seq AS INTEGER START WITH 100 INCREMENT BY 1] 在org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)〜[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE] 在org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)〜[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE] ...省略了158个常用帧 引起:org.springframework.jdbc.datasource.init.ScriptStatementFailedException:无法在资源类路径资源[schema.sql]的第1行执行SQL脚本语句:CREATE SEQUENCE voucher_id_seq AS INTEGER START WITH 100 INCREMENT BY 1;嵌套异常是java.sql.SQLSyntaxErrorException:对象名已存在:语句中的VOUCHER_ID_SEQ [CREATE SEQUENCE voucher_id_seq AS INTEGER START WITH 100 INCREMENT BY 1] 在org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:474)〜[spring-jdbc-4.0.9.RELEASE.jar:4.0.9.RELEASE] 在org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:208)〜[spring-jdbc-4.0.9.RELEASE.jar:4.0.9.RELEASE] 在org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:49)〜[spring-jdbc-4.0.9.RELEASE.jar:4.0.9.RELEASE] 在org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.initDatabase(EmbeddedDatabaseFactory.java:159)〜[spring-jdbc-4.0.9.RELEASE.jar:4.0.9.RELEASE] 在org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.getDatabase(EmbeddedDatabaseFactory.java:132)〜[spring-jdbc-4.0.9.RELEASE.jar:4.0.9.RELEASE] 在org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder.build(EmbeddedDatabaseBuilder.java:251)〜[spring-jdbc-4.0.9.RELEASE.jar:4.0.9.RELEASE] at com.siemens.ott.TestDatabaseConfig.dataSource(TestDatabaseConfig.java:46)〜[test-classes /:na] at com.siemens.ott.TestDatabaseConfig $$ EnhancerBySpringCGLIB $$ 6a150586.CGLIB $ dataSource $ 1()〜[spring-core-4.1.6.RELEASE.jar:na] at com.siemens.ott.TestDatabaseConfig $$ EnhancerBySpringCGLIB $$ 6a150586 $$ FastClassBySpringCGLIB $$ 125e7bce.invoke()〜[spring-core-4.1.6.RELEASE.jar:na] 在org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)〜[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE] at org.springframework.context.annotation.ConfigurationClassEnhancer $ BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:309)〜[spring-context-4.1.6.RELEASE.jar:4.1.6.RELEASE] at com.siemens.ott.TestDatabaseConfig $$ EnhancerBySpringCGLIB $$ 6a150586.dataSource()〜[spring-core-4.1.6.RELEASE.jar:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)〜[na:1.8.0_45] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)〜[na:1.8.0_45] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)〜[na:1.8.0_45] 在java.lang.reflect.Method.invoke(Method.java:497)〜[na:1.8.0_45] 在org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)〜[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE] ...省略了159个常用帧 引起:java.sql.SQLSyntaxErrorException:对象名已存在:语句中的VOUCHER_ID_SEQ [CREATE SEQUENCE voucher_id_seq AS INTEGER START WITH 100 INCREMENT BY 1] at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)〜[hsqldb-2.3.2.jar:2.3.2] at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)〜[hsqldb-2.3.2.jar:2.3.2] at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source)〜[hsqldb-2.3.2.jar:2.3.2] at org.hsqldb.jdbc.JDBCStatement.execute(Unknown Source)〜[hsqldb-2.3.2.jar:2.3.2] 在org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:459)〜[spring-jdbc-4.0.9.RELEASE.jar:4.0.9.RELEASE] ...省略了175个常用帧 引起:org.hsqldb.HsqlException:对象名已存在:VOUCHER_ID_SEQ
答案 0 :(得分:0)
对于可能遇到这种情况的其他人来说,问题出现在意想不到的地方:loader = AnnotationConfigWebContextLoader
。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { TestConfiguration.class }, loader = AnnotationConfigWebContextLoader.class)
@ActiveProfiles("test")
@TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
简单地删除罪魁祸首解决了所有问题。 现在schema.sql只执行一次。