【问题标题】:Does JPA's commit() method make entity detached?JPA 的 commit() 方法是否使实体分离?
【发布时间】:2015-08-12 12:14:19
【问题描述】:

我现在一直在搜索 JPA 实体生命周期。 但是现在,关于实体生命周期存在一些缺失点。我在其中一个 stackoverflow 帖子中找到了以下图形,请记住,此图已被投票。

根据这张图,当我们持久化实体时,它就变成了托管的。 好的 。没问题 。 当我们提交时,数据进入数据库。好的 。 没问题。 但是图表向我们展示了这个提交操作使实体分离! 让我们看看下面的伪代码。

entityManager.persist(entity);
transaction.commit(); // action completed and entity has become detached.(According to the diagram.)
entityManager.remove(entity); //Attention this step please .

在上一步(提交步骤)。那么如何才能移除一个分离的对象呢? 如果这个实体变得分离,我们都知道不可能管理一个分离的实体,因为它不再与持久化上下文关联。

那么如何才能移除一个分离的对象呢?你能在这一点上澄清一下吗? 提前致谢!

【问题讨论】:

  • 你的意思是“entityManager.remove(entity); // 实体已经在这里分离了?”请澄清这个细节
  • 我的意思是“如果实体在提交后变得分离(根据图表),怎么可能删除这个实体?因为分离意味着它不再与持久性上下文相关联并且不能执行任何操作在分离实体上“
  • 取决于 PersistenceContext ...参见datanucleus.org/products/accessplatform_4_2/jpa/… EM.close 可以是分离它的操作,具体取决于上下文

标签: java hibernate jpa


【解决方案1】:

两件事: 状态 remove 和 detached 是不同的:Removed 表示该实体仍处于托管状态,并将在刷新时触发持久层中的删除,Detached 表示该实体不再处于托管状态,并且对其所做的更改将不会不会报告给数据库。

您的实体状态与entityManager 相关。 Managed 表示EM 跟踪对其所做的所有更改,并将在刷新时将它们报告到数据库中。

您必须了解,报告对数据库的更改在事务之外没有任何意义(JPA 仅支持对 DB 的事务访问,并且仅在隔离级别 READ_COMMITED 中支持)。

一旦检索到实体的事务已过期,跟踪实体上的更改毫无意义,因为EntityManager 将无法在事务之外更改数据库状态。

这就是为什么JPA 中的EntityManager 旨在为每个工作单元创建(与persistenceUnit 相反,即为整个应用程序创建一次的entityManagerFactory)。

因此,EntityManager 应该与事务具有相同的范围,并且应该在提交后立即释放(当您让容器为您管理 entityManager 生命周期时就是这种情况)。

这也是JPA不支持嵌套事务的原因。

【解决方案2】:

实体可以通过以下方式之一(可能有更多方式)分离:

  1. 当事务(在事务范围的持久性上下文中)提交时,由持久性上下文管理的实体将分离。

  2. 如果应用程序管理的持久性上下文关闭,所有托管实体都将分离。

  3. 使用清除方法

  4. 使用分离方法

  5. 回滚

  6. 在扩展持久性上下文中,当移除有状态 bean 时,所有托管实体都将分离。

我认为问题可能在于应用程序管理、用户管理、扩展持久性上下文之间的差异。

【讨论】:

  • 您好,请看 pL4GU33 的回答。您的答案似乎不匹配。谢谢
  • 不,这是误解,他说的都是真的。正如我在回答中所说,图片在 TRANSACTION 范围上下文中是正确的)但并非在所有可能的情况下。 (就像我的例子)
  • 是的,我认为混淆可能是因为持久性上下文的范围。它是应用程序管理的吗? EM 是否创建类似:EntityManager em = emf.createEntityManager(); ?如果删除操作删除了实体,则实体在删除之前被管理,这意味着持久性上下文(em)的范围不是事务(扩展或应用程序管理)。否则会抛出异常docs.oracle.com/javaee/6/api/javax/persistence/…
  • 谢谢大家。首先,我应该了解应用管理上下文和事务管理上下文之间的区别。
  • 在我的经验中奇怪的是,当事务(至少由 Spring 使用 @Transactional 管理)不分离实体时。我只能通过在新事务中调用 setter 来将新的更新值保存到数据库中,而无需解决合并方法
【解决方案3】:

JPA 规范:

3.3 Persistence Context Lifetime and Synchronization Type
...
An EntityManager with an extended persistence context maintains its references to the entity objects
after a transaction has committed. Those objects remain managed by the EntityManager, and they can
be updated as managed objects between transactions.
...
3.3.2 Transaction Commit
The managed entities of a transaction-scoped persistence context become detached when the transaction
commits; the managed entities of an extended persistence context remain managed.

请注意,应用程序管理的实体管理器(通常在 Java SE 中使用)总是使用扩展的持久性上下文。

所以对你的问题的简短回答是:当使用事务范围的 PC 时,提交会导致分离;使用扩展 PC 时,commit 不会导致分离。

【讨论】:

    【解决方案4】:

    这张图片来自openjpa,但是IMO(欢迎其他意见)有点不对劲?! (在具有 TRANSACTION Scope 的 EE 中可以) 但是在这样的 JAVA SE 示例中: ....

    EntityTransaction et = em.getTransaction();
    et.begin();
    em.persist(entity);
    et.commit();
    System.out.println(em.contains(entity)); // true
    em.detach(entity);
    System.out.println(em.contains(entity)); // false
    entity = em.merge(entity);
    System.out.println(em.contains(entity)); // true
    

    实体在分离方法后分离。提交后它停留在实体持久化上下文中。

    对于您的问题:当您有一个分离的对象时,您可以使用合并将其重新附加到持久性上下文。

    【讨论】:

    • 我觉得这张照片让我很困惑。图片显示了 commit işt 变为 detach 后的我们。但我可以看到实体仍处于持久性上下文中。谢谢。
    • 你知道如何在 JPA 中改变这种行为吗?
    • 我也有同样的行为。 em.commit() 不会分离它,但 em.rollback 会。你能解释一下吗?谢谢。
    猜你喜欢
    • 2015-08-10
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 2014-11-24
    • 2012-10-19
    • 1970-01-01
    • 2017-06-05
    相关资源
    最近更新 更多