【问题标题】:javax.persistence.EntityNotFoundException: deleted entity passed to persistjavax.persistence.EntityNotFoundException:已删除的实体传递给持久化
【发布时间】:2014-11-22 11:38:58
【问题描述】:

我使用 spring + JPA 作为 orm 框架。我的项目层结构类似于 web --> Service --> Domain DAO --> genericDAO。 在 genericDAO 中,我使用 @PersistenceContext 注入 EntityManager。

genericDAO.delete(Object o) {
    o = entityManager.merge(o);
    entityManager.remove(o);
}

genericDAO.saveOrUpdate(Object o) {
    entityManager.merge(o);
    entityManager.flush();
}

在服务层的一种方法中,我有以下操作。

// delete order item if already exists.
Order order = getOrderFromSession();
if (CollectionUtils.isNotEmpty(orderItems)) {
  Iterator<OrderItem> iterator = orderItems.iterator();
  while (iterator.hasNext()) {
     OrderItem orderItem = iterator.next();
     iterator.remove();
     orderDAO.deleteOrderItem(orderItem); // Which internall calls genericDAO.delete()
  }
}
//orderDAO.saveOrder(order) // line  Y
//Now create fresh order items submitted by jsp form.
for (ProductVO productVO : productList) {
 if (productVO.getQuantity() > 0) {
    orderItem = new OrderItem();
    Product product = productDAO.getProductByCode(productVO.getCode()); // line X
    orderItem.populateOrderItemByProduct(product, productVO.getQuantity(), order);
    order.addOrderItem(orderItem);
 }
}

第 X 行使用 hql 检索产品实体。但是当执行第 X 行时,我得到以下错误。 javax.persistence.EntityNotFoundException:已删除的实体传递给持久化:[core.entity.OrderItem#]。

我不明白订单项是否已在实体管理器中标记为已删除,为什么它会尝试保留。

当我取消注释行 Y 时,它在内部刷新实体管理器,它工作正常。我不明白为什么它需要在执行第 X 行之前刷新实体管理器

【问题讨论】:

    标签: spring hibernate jpa entitymanager transactional


    【解决方案1】:

    这是hibernate documentation的引述

    事务性持久实例(即加载、保存的对象, 由 Session 创建或查询)可以由 应用程序,并且对持久状态的任何更改都将被持久化 当 Session 被刷新时。无需调用特定方法(如 update(),它具有 不同的目的)使您的修改持久化。最多 更新对象状态的直接方法是 load() 它 然后在 Session 打开时直接操作它。

    有时这种编程模型是 效率低下,因为它需要在同一个会话中同时使用 SQL SELECT 加载一个对象和一个 SQL UPDATE 以保持其更新状态。 Hibernate 通过使用分离的实例提供了另一种方法。

    但我会尽量简单地解释一下。您的方法getOrderFromSession() 是事务性的,休眠对象在其中打开了会话,但是当对象order 返回给您时,它已与会话分离并且休眠不知道您在用它做什么,直到您坚持他再次。因此,对于已删除的项目,当您保存该对象时,hibernate 会发现,在此之前,处于休眠状态的对象具有与 getOrderFromSession() 返回时相同的状态。

    这里有detailed explanation

    更新:

    当你在 hibernate 中删除对象时,java 中的对象变成瞬态的。它在java中仍然存在,删除后就可以使用了。

    Session.delete() 将从数据库中删除对象的状态。您的 但是,应用程序仍然可以保存对已删除对象的引用。 最好将 delete() 视为创建一个持久实例, 瞬态。

    【讨论】:

    • 由于实体管理器是共享的,删除订单项目和加载产品发生在同一个实体管理器中。那为什么会报错呢?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-16
    • 1970-01-01
    • 2013-06-03
    • 2013-06-26
    • 1970-01-01
    • 2017-04-01
    • 2018-09-22
    相关资源
    最近更新 更多