我正在开发一个新的Spring Batch(3.0.3.RELEASE)应用程序,在该应用程序中将访问多个数据库。为了测试,我们使用HSQLDB(2.3.2)作为嵌入式数据库。
在我的应用程序上下文中,我有以下内容。
<jdbc:embedded-database id="dataSource">
</jdbc:embedded-database>
<jdbc:embedded-database id="proDataSource">
<jdbc:script location="classpath:script-tables.sql" />
<jdbc:script location="classpath:script-constraints.sql" />
</jdbc:embedded-database>
<jdbc:embedded-database id="altDataSource">
<jdbc:script location="classpath:script-alt-tables.sql" />
</jdbc:embedded-database>
当我在Eclipse中运行单个测试时,事情很好。当我从命令行构建时,在第一次测试之后,我得到错误
Failed to execute SQL script statement at line 3 of resource class path resource [script-promrkt-promo.sql]
object name already exists: PROMRKT
在我看来,EmbeddedDatabaseFactory中的填充过程正在接收已填充的数据库。据我所知,每次测试后都没有执行SHUTDOWN,HSQLDB将已经填充的数据库留在内存中。
我已经重新审核了文档,并在Spring Doc中显示了一个明确的关闭命令。但是,如果Spring在我的测试开始时启动嵌入式数据库,为什么在测试完成时它没有关闭它?
答案 0 :(得分:3)
日志消息抱怨的脚本不在您的配置中。我认为它在其他地方被执行了吗?如果是这种情况,您可能需要在测试中添加@DirtiesContext
,以便Spring不会缓存上下文(我假设您正在使用SpringJunit4Runner
与@ContextConfiguration
@DirtiesContext
,但无法确定,因为您的实际测试不在问题中)。
如果我的假设是正确的,Spring会缓存上下文,以提高运行单元测试套件的性能。如果您的测试以可能影响其他测试的方式修改上下文(例如在一个测试中运行脚本需要在其他测试中再次运行),则使用{{1}}标记测试,而Spring不会缓存上下文。您可以在方法或类级别使用注释。您可以在此处详细了解注释:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/annotation/DirtiesContext.html
答案 1 :(得分:1)
我花了很多时间看这个并阅读Spring Framework文档(喘气!)并通过代码进行跟踪。 4.1 spring核心有一些有趣的变化,特别是测试。
我发现ApplicationContext现在缓存在JVM级别。如果第二个测试要求上下文,TestContext首先在其缓存中查看是否有其他测试已经要求相同的配置。
我的一些测试配置文件。具有不同配置文件但具有相同@ContextConfiguration的测试会导致使用应用的配置文件重新加载该上下文。当&#34; Bean Loader&#34;在创建嵌入式数据库时,EmbeddedDatabaseFactory没有考虑嵌入式数据库(在内存HSQLDB中)可能已经从以前的测试中创建或缓存,并且不需要重新初始化。
因此,我在EmbeddedDatabaseFactory.initDatabase()中添加了一些逻辑,检查数据库是否已经存在,然后重新初始化&amp;运行DatabasePopulator。
List existingDataBases = org.hsqldb.DatabaseManager.getDatabaseURIs();
boolean isExisting = false;
String localDBName = StringUtils.lowerCase(this.databaseName);
for (Object object : existingDataBases) {
if (object.toString().contains(localDBName)) {
isExisting = true;
break;
}
}
// Now populate the database
if (!isExisting && this.databasePopulator != null) {
(当然,对于弹簧需要的东西来说,这并不是很合理,但它可以解决问题)
在我看来,它看起来像是EmbeddedDatabaseFactory和TestContext缓存机制的部分问题。我的&#34; jdbc:嵌入式数据库&#34;定义没有与之关联的任何配置文件。为什么缓存需要重新创建它们而不是从现有的缓存bean中加载它们?
答案 2 :(得分:0)
每次创建新对象时,您都可以尝试通过generateUniqueName(true)
设置唯一名称来强制创建新的嵌入式数据库。
以下是一个例子:
embeddedDatabase = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.generateUniqueName(true)
.addScripts("db/sql/create-db.sql", "db/sql/insert-data.sql")
.build();