ajk*_*ret 5 java database junit h2 maven
我们有一个使用Spring和MAVEN的Java项目.在这个项目中,我们在内存中使用H2数据库在我们的DAO/Repository层上执行几个测试.
经过几次测试后,但并不总是,我们得到以下错误:
org.h2.jdbc.JdbcSQLException: Table "WEATHER" not found; SQL statement:
Run Code Online (Sandbox Code Playgroud)
如果单独执行JUnit测试,它将永远不会失败.错误出现时没有模式.
我怀疑下面关于URL连接的RUNSCRIPT语句没有完成,并且单元测试开始时,即执行是异步执行的.
这是连接声明:
String jdbcUrl = "jdbc:h2:mem:WeatherAPI;MODE=MySQL;DB_CLOSE_ON_EXIT=TRUE;TRACE_LEVEL_SYSTEM_OUT=1;INIT=runscript from 'src/test/resources/sql/weatherapi.sql'"
Run Code Online (Sandbox Code Playgroud)
这个想法是每次测试都会重置数据库.
以下是获取DataSource对象的代码片段:
private static java.sql.DataSource ds = null;
public static DataSource getDs() {
if(this.ds==null) {
try {
this.ds = manualCreateDataSource();
} catch (Exception e) {
logger.error("Could not initialize Datasource", e);
throw new RuntimeException("Could not initialize Datasource");
}
}
return this.ds;
}
public static DataSource manualCreateDataSource() {
String driverClass = "org.h2.jdbcx.JdbcDataSource";
String jdbcUrl = "jdbc:h2:mem:WeatherAPI;MODE=MySQL;DB_CLOSE_ON_EXIT=TRUE;TRACE_LEVEL_SYSTEM_OUT=1;INIT=runscript from 'src/test/resources/sql/weatherapi.sql'";
int maxPoolSize = 20;
int minPoolSize = 5;
int unreturnedConnectionTimeout = 10;
int idleConnectionTestPeriod = 200;
int maxIdleTime = 1000;
int maxStatementsPerConnection = 5;
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setJdbcUrl(jdbcUrl);
ds.setMaxPoolSize(maxPoolSize);
ds.setMinPoolSize(minPoolSize);
ds.setInitialPoolSize(minPoolSize);
ds.setUnreturnedConnectionTimeout(unreturnedConnectionTimeout);
ds.setIdleConnectionTestPeriod(idleConnectionTestPeriod);
ds.setMaxIdleTime(maxIdleTime);
ds.setMaxStatementsPerConnection(maxStatementsPerConnection);
try {
ds.setDriverClass(driverClass);
} catch (PropertyVetoException e) {
logger.error("error setting driver class", e);
}
return ds;
}
Run Code Online (Sandbox Code Playgroud)
这里是weatherapi.sql脚本的片段:
CREATE SCHEMA IF NOT EXISTS `WeatherAPI`;
USE `WeatherAPI`;
DROP TABLE IF EXISTS `Weather`;
CREATE TABLE IF NOT EXISTS `Weather` (
id int(11) NOT NULL AUTO_INCREMENT,
location char(3) NOT NULL,
period varchar(8) NOT NULL,
duration char DEFAULT NULL,
payload TEXT,
created timestamp NULL DEFAULT NULL,
lastmodified timestamp NULL DEFAULT NULL,
version int(11) NOT NULL, PRIMARY KEY (id)
);
Run Code Online (Sandbox Code Playgroud)
我怀疑这是一个竞争条件。根据文档,该脚本是为连接到数据库的每个客户端执行的。由于您总是在重新创建表之前删除该表,因此当测试已经运行并且第二个客户端连接到数据库时,Weather可能会发生该表在. 可能是另一个并行运行的测试或同一测试中的第二个线程。ABAB
如果是这种情况,您可以尝试RunScript在方法中使用该工具,manualCreateDataSource()而不是INITJDBC 连接 URL 中的参数:
String jdbcUrl = "jdbc:h2:mem:WeatherAPI;MODE=MySQL;DB_CLOSE_ON_EXIT=TRUE;TRACE_LEVEL_SYSTEM_OUT=1;"
RunScript.execute(jdbcUrl, sa, "", "src/test/resources/sql/weatherapi.sql", null, false);
Run Code Online (Sandbox Code Playgroud)
此外,您需要通过添加或更好地静态初始化实例变量来实现getDs()线程安全:synchronizedds
private static java.sql.DataSource ds = manualCreateDataSource();
public static DataSource getDs() {
return ds;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2529 次 |
| 最近记录: |