【问题标题】:Atomikos rollback doesn't clear JPA persistence context?Atomikos 回滚不清除 JPA 持久性上下文?
【发布时间】:2010-06-14 05:08:46
【问题描述】:

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

【问题讨论】:

  • DAO 从应用程序中获取他们的 EntityManager,而不是 @PersistenceContext 注释(长篇大论……)。检查我的 EntityManagerFactory 后,我发现它不是容器管理的(例如,它是应用程序管理的),并且 persistenceContextType 是扩展的,而不是事务。我猜对 emf.createEntityManager() 的简单调用与 @PersistenceContext 注释不一样!!!如何正确手动设置我的 EntityManagers - 例如事务和容器管理...我需要在事务回滚时自动清除持久性上下文。

标签: hibernate jpa jta c3p0 autocommit


【解决方案1】:

这很奇怪。来自 JPA 规范:

3.3.2 事务回滚

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

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

【讨论】:

  • 我的看法是一样的。但是,Hibernate Entity Manager 文档说“扩展上下文意味着在检索实体管理器时创建持久性上下文(使用 EntityManagerFactory.createEntityManager(...) )并在关闭实体管理器时关闭。”我通过 emf.createEntityManager() 调用创建了我的 EntityManager,这显然创建了一个扩展的持久性上下文。也许我需要打开另一个关于如何在没有 @PersistenceContext 的情况下创建 JTA 事务实体管理器并将其注入 DAO 的问题。
【解决方案2】:

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

Problem creating JPA EntityMananger in Spring Context

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2014-01-08
    • 2023-03-18
    • 2014-11-12
    • 2013-10-31
    • 2010-09-07
    • 2013-05-15
    相关资源
    最近更新 更多