我有一个 Spring/JPA/Hibernate 应用程序,并试图让它通过我针对 H2 和 MySQL 的 Junit 集成测试。目前我使用 Atomikos 进行事务处理,使用 C3P0 进行连接池。
尽管我尽了最大努力,但我的 DAO 集成其中一项测试因 org.hibernate.NonUniqueObjectException 而失败。在失败的测试中,我使用“new”运算符创建了一个对象,设置 ID 并在其上调用persist。
@Test
@Transactional
public void save_UserTestDataNewObject_RecordSetOneLarger() {
int expectedNumberRecords = 4;
User newUser = createNewUser();
dao.persist(newUser);
List<User> allUsers = dao.findAll(0, 1000);
assertEquals(expectedNumberRecords, allUsers.size());
}
在前面的测试方法中,我做了同样的事情(createNewUser() 是一个帮助方法,它每次都创建一个具有相同 ID 的对象)。我确信创建和持久化具有相同 ID 的第二个对象是原因,但每个测试方法都在自己的事务中,并且我创建的对象绑定到私有测试方法变量。我什至可以在日志中看到 Spring Test 和 Atomikos 正在回滚与每个测试方法关联的事务。
我原以为回滚也会清除持久性上下文。凭直觉,我在错误测试方法的开头添加了对 dao.clear() 的调用,问题就消失了!!所以回滚并没有清除持久化上下文???如果不是,那是谁呢??
我的 EntityManagerFactory 配置如下:
<bean id="myappTestLocalEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myapp-core" />
<property name="persistenceUnitPostProcessors">
<bean class="com.myapp.core.persist.util.JtaPersistenceUnitPostProcessor">
<property name="jtaDataSource" ref="myappPersistTestJdbcDataSource" />
</bean>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="database" value="$DS{hibernate.database}" />
<property name="databasePlatform" value="$DS{hibernate.dialect}" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.factory_class">com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory</prop>
<prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.format_sql">true"</prop>
<prop key="hibernate.use_sql_comments">true</prop>
</property>
</bean>