【问题标题】:Within JTA transaction (using container managed transaction), executeUpdate mehtod for explicit Query does immediate commit在 JTA 事务中(使用容器管理事务),显式查询的 executeUpdate 方法会立即提交
【发布时间】:2015-02-18 16:21:15
【问题描述】:

在 JBOSS 7.1 AS 中,我使用的是容器管理事务。对于每个请求,我都会进行几次实体更新。大多数实体使用 EntityManager 中的“插入、合并、刷新”方法来管理更新。但是,有一个实体使用显式查询在数据库上执行“executeUpdate”(参见下面的代码 sn-p)。此 sql 更新立即提交到数据库,并且与容器管理的事务(如其他实体更新)不一致。无论如何,是否将显式 sql 更新(下面的更新)与容器管理的事务对齐?我正试图让回滚工作并且这个 sql 更新没有被回滚。除了这个之外,所有其他实体更新和插入都工作正常。感谢您的所有帮助。

代码sn-p:

entityManager.createQuery 
 ( "UPDATE Balance a SET a.balanceValue = :newValue WHERE a.balanceId =:balanceId AND a.balanceValue = :currentValue" ) .setParameter("balanceId", cb.getBalanceId()) .setParameter("currentValue", cb.getBalanceValue()).setParameter("newValue", newAmt).executeUpdate();

附加代码:(下面的代码使用 Bean 管理的事务,但 CMT 的行为也相同)

            ut.begin();
        ChargingBalance bal2 = entityManager.find(ChargingBalance.class, 13);
        bal2.setResetValue((new Date()).getTime());
        String UPDATE_BALANCE_AND_EXPIRYDATE_EQUAL = "UPDATE ChargingBalanceValue a"
                + "  SET a.balanceValue = :newValue "
                + "  WHERE a.balanceId = :balanceId";

        Query query = entityManager.createQuery(UPDATE_BALANCE_AND_EXPIRYDATE_EQUAL)
                .setParameter("balanceId", 33)
                .setParameter("newValue", 1000l);

        /*The executeUpdate command gets committed to DB before ut.commit is executed */
        query.executeUpdate();

        /* This below only commits changes on ResetValue */
        ut.commit();

        ut.begin();
        ChargingBalance bal = entityManager.find(ChargingBalance.class, 23);
        bal.setResetValue(1011l);

        query = entityManager.createQuery(UPDATE_BALANCE_AND_EXPIRYDATE_EQUAL)
                .setParameter("balanceId", 33)
                .setParameter("newValue", 2000l);
        query.executeUpdate();

        /* This rollback doesn't rollback changes executed by executeUpdate, but it rollbacks ResetValue change */
        ut.rollback();

【问题讨论】:

  • 也尝试添加一些相关代码,“我做了几个实体更新。大多数实体使用“插入、合并、刷新”,由此不清楚您如何更新实体以及您如何得出大多数实体使用插入、合并、刷新等。
  • 使用哪个 JPA 实现?
  • 我添加了一些额外的代码。我正在使用 JPA 2.0 的 Hibernate 实现。 org.hibernate:hibernate-entitymanager:4.2.7.SP1
  • 任何帮助将不胜感激。我在这个问题上停留了一段时间。

标签: jpa jboss7.x entitymanager ejb-3.1 jta


【解决方案1】:
  • executeUpdate 命令在 ut.commit 之前被提交到 DB 执行

    它可能已将更改刷新到数据库中,但没有像在 BMT 中那样提交。

    您可以尝试回滚并验证它是否确实已提交并且在事务中。

  • 以下仅提交对 ResetValue 的更改

    当您执行本机或 JPQL/HQL 查询时,它将直接对数据库进行更改,而 EntityManager 可能不知道这些更改。

    因此,EntityManager 不会隐式刷新托管实体,并且可能包含过时/陈旧的数据。

  • 您可以通过文档了解更多详细信息,以下是摘录。

    JPQL UPDATE 查询提供了另一种更新实体的方法 对象。与 SELECT 查询不同,后者用于从 数据库,UPDATE 查询不会从数据库中检索数据, 但在执行时,更新指定实体对象的内容 数据库。

    使用 UPDATE 查询更新数据库中的实体对象可能是 比检索实体对象更有效,然后 更新它们,但应谨慎使用,因为绕过 EntityManager 可能会中断其与数据库的同步。为了 例如,EntityManager 可能不知道缓存的实体 其持久性上下文中的对象已被 UPDATE 修改 询问。因此,最好使用单独的 用于 UPDATE 查询的 EntityManager。

【讨论】:

  • 感谢您的回复!我发现了问题。它与 JBOSS 7.2 问题有关,无法通过 UI 更新数据源页面上的“JTA”选项。我认为将 persistence.xml 上的配置设置为 transaction-type=JTA 就足够了。然而,我错了。当我手动更新standalone.xml 并重新启动JBOSS。在 CMT 提交其余事务的同时提交了显式查询。感谢您的所有帮助!
猜你喜欢
  • 2011-12-10
  • 1970-01-01
  • 2017-02-05
  • 2015-01-14
  • 2014-02-22
  • 2015-06-06
  • 1970-01-01
  • 2020-12-07
  • 2015-10-20
相关资源
最近更新 更多