0

我有一个 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>
4

2 回答 2

1

这种情况下的问题最终是我有一个应用程序管理的扩展事务实体管理器被注入到我的 DAO 中。原因可以在这里找到:

在 Spring 上下文中创建 JPA EntityMananger 的问题

一旦我修复了我的实体经理 - 一切正常。

于 2010-06-15T18:53:23.630 回答
1

这很奇怪。从 JPA 规范:

3.3.2 事务回滚

对于事务范围和扩展的持久性上下文,事务回滚会导致所有 预先存在的托管实例和删除的实例变得分离。实例的状态将是事务回滚时实例的状态。事务回滚通常会导致持久性上下文在回滚时处于不一致的状态。特别地,版本属性的状态和生成的状态(例如,生成的主键)可能不一致。因此,以前由持久性上下文管理的实例(包括在该事务中持久化的新实例)可能无法以与其他分离对象相同的方式重用——例如,它们在传递给合并操作时可能会失败。

我阅读上述部分的方式是,当事务回滚时,JPA 应该清除其持久性上下文。

于 2010-06-14T12:51:55.790 回答