java 使用实体管理器的 Spring junit 测试不会在 H2 文件系统数据库中插入数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25187016/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring junit test using Entity Manager doesn't insert data in H2 filesystem database
提问by Mathias G.
First my setup:
首先我的设置:
- JUnit version: 4.11
- H2 version: 1.3.174
- Spring version: 4.0.5.RELEASE
- Hibernate version: 4.1.0.Final
- JUnit 版本:4.11
- H2 版本:1.3.174
- 春季版本:4.0.5.RELEASE
- 休眠版本:4.1.0.Final
A little context:
一点背景:
I have a REST web service that is deployed on a Tomcat webserver and that has a h2 database underneath. I have a REST service that doesn't have any POST/PUT methods. When writing an integration test for it, I manually added the entries in the DB using the H2 console and placed the h2-file on the server. Finally my integration test calls the REST service and the data I manually injected in the DB is returned and the test succeeds. This is not maintainable and it would be great to inject for every test the data I need (this approach can be used for other integration tests later...). The goal is to inject data into the same database as the application deployed on Tomcat is using.
我有一个 REST Web 服务,它部署在 Tomcat 网络服务器上,下面有一个 h2 数据库。我有一个没有任何 POST/PUT 方法的 REST 服务。在为其编写集成测试时,我使用 H2 控制台手动在数据库中添加条目并将 h2 文件放在服务器上。最后我的集成测试调用 REST 服务,返回我手动注入数据库的数据,测试成功。这是不可维护的,最好为每个测试注入我需要的数据(这种方法以后可以用于其他集成测试......)。目标是将数据注入到部署在 Tomcat 上的应用程序所使用的同一个数据库中。
I thought it would be very easy and I wrote an integration test reusing the same application context that is used on the server side:
我认为这会很容易,因此我编写了一个集成测试,重用了在服务器端使用的相同应用程序上下文:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="${database.url}" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="be.wiv_isp.healthdata.catalogue.domain" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
where the database url is defined in a properties fil:
其中数据库 url 在属性文件中定义:
database.url=jdbc:h2:file:${healthdata.working.dir}/database/database-catalogue;AUTO_SERVER=true
Then I annotated the EntityManager as being my PersistenceContext and wrote a simple unit test:
然后我将 EntityManager 注释为我的 PersistenceContext 并编写了一个简单的单元测试:
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:/applicationContext-it-test.xml"})
public class H2Test {
@PersistenceContext
private javax.persistence.EntityManager em;
DataCollectionDefinition dcd = new DataCollectionDefinitionBuilder()
.withId(Long.valueOf(1))
.build();
@Before
public void init() {
em.persist(dcd);
em.flush();
em.clear();
}
@Test
public void testGet() {
DataCollectionDefinition found = em.find(DataCollectionDefinition.class, 1);
Assert.assertEquals(found, dcd);
}
}
This test runs fine! However when I put a breakpoint after the data is flushed using the EntityManager and I connect to my H2 filesystem database, nothing is injected!
这个测试运行良好!但是,当我在使用 EntityManager 刷新数据后设置断点并连接到我的 H2 文件系统数据库时,没有注入任何内容!
Now I was wondering. Is it normal that JUnit using Spring NEVER actually persists the data in the database and keeps it somewhere in memory? And is there a way to persist it anyway, so I could use it for prefilling of the database for my integration tests.
现在我想知道。使用 Spring 的 JUnit 永远不会将数据保存在数据库中并将其保存在内存中的某处是否正常?无论如何,有没有办法坚持它,所以我可以用它来为我的集成测试预填充数据库。
For now I have a workaround storing my data using good old JDBC, but it's dirty and I think it should work using Spring and above all I would like to understand why the data is not persisted using the EntityManager of Spring...
现在我有一个使用旧 JDBC 存储数据的解决方法,但它很脏,我认为它应该使用 Spring 工作,最重要的是我想了解为什么不使用 Spring 的 EntityManager 来持久化数据......
回答by geoand
What's going on is a combination of how JPA works and what Spring does when running transactional tests.
发生的事情是 JPA 的工作方式和 Spring 在运行事务测试时所做的工作的结合。
First, JPA when an entity is persisted in JPA, that does not mean that the data is actually persisted to the database. Usually the data will be pushed to the database when the current transaction commits, or when you flush the entity manager. Check out thisSO answer among the many you can find with a simple google search.
首先,JPA 当实体持久化在 JPA 中时,并不意味着数据实际上持久化到数据库中。通常在当前事务提交时,或者刷新实体管理器时,数据会被推送到数据库中。通过简单的谷歌搜索,您可以在众多答案中查看这个SO 答案。
Second, when Spring runs a test that is annotated with @Transactional
, then by default it will rollback the transaction when the test completes. Check thisof many similar issues. In order to override that default behavior, you need to use @Rollback(false)
.
其次,当 Spring 运行带有 注释的测试时,@Transactional
默认情况下它会在测试完成时回滚事务。检查这许多类似的问题。为了覆盖该默认行为,您需要使用@Rollback(false)
.
The data gets written to the file when you use JDBC, because you are running the statements outside of the Transaction Spring has created for the test and therefore the default rollback has no data to revert.
当您使用 JDBC 时,数据会写入文件,因为您正在 Spring 为测试创建的事务之外运行语句,因此默认回滚没有要恢复的数据。
回答by Xiao Peng - ZenUML.com
Add @Commit at class level or method level. Check this
在类级别或方法级别添加@Commit。检查这个
When declared as a class-level annotation, @Commit defines the default commit semantics for all test methods within the test class hierarchy. When declared as a method-level annotation, @Commit defines commit semantics for the specific test method, potentially overriding class-level default commit or rollback semantics.
当声明为类级别注释时,@Commit 为测试类层次结构中的所有测试方法定义默认提交语义。当声明为方法级别的注解时,@Commit 为特定的测试方法定义了提交语义,可能会覆盖类级别的默认提交或回滚语义。