【问题标题】:java.lang.IllegalArgumentException: Removing a detached instance com.test.User#5java.lang.IllegalArgumentException:删除分离的实例 com.test.User#5
【发布时间】:2013-06-06 07:35:38
【问题描述】:

我有一个使用 JPA (transaction-type="JTA")、hibernate 作为提供者的 java EE 项目。我写我的 bean 来处理 CRUD 的事情。在 JBOSS 7 AS 中运行的程序。

我有一个 EntityManagerDAO :

@Stateful
public class EntityManagerDao implements Serializable {

    @PersistenceContext(unitName = "dtdJpa")
    private EntityManager entityManager;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public Object updateObject(Object object) {
        object = entityManager.merge(object);
        return object;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void createObject(Object object) {
        entityManager.persist(object);
    }

    public void refresh(Object object) {
        entityManager.refresh(object);
    }

    public <T> T find(Class<T> clazz, Long id) {
        return entityManager.find(clazz, id);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void deleteObject(Object object) {
        entityManager.remove(object);
    }
}

但是当我调用deleteObject 时,就会出现这个异常。

java.lang.IllegalArgumentException: 删除一个分离的实例 com.test.User#5

这是怎么引起的,我该如何解决?

【问题讨论】:

    标签: jpa sql-delete entitymanager illegalargumentexception


    【解决方案1】:

    EntityManager#remove() 仅适用于在当前事务/上下文中管理的实体。在您的情况下,您在较早的事务中检索实体,将其存储在 HTTP 会话中,然后尝试在不同的事务/上下文中将其删除。这根本行不通。

    您需要检查该实体是否由EntityManager#contains() 管理,如果不是,则使其由EntityManager#merge() 管理。

    基本上,您的业务服务类的delete() 方法应如下所示:

    em.remove(em.contains(entity) ? entity : em.merge(entity));
    

    【讨论】:

    • @BalusC In em.remove(em.contains(entity) ? entity : em.merge(entity)); ,如果 em(contains(entity) 为假,那么您是否要删除 entityToBeRemoved = em.merge(entity) , entityToBeRemoved?您是否要删除从 em.merge(entity) 返回的内容?
    • 因为根据我提到的问题中的答案,您需要:a = em.merge(a); // 合并并将 a 分配给附加的实体 em.remove(a); // 移除附加的实体
    • @BalusC 在使用 em.remove(em.contains(entity) ? entity : em.merge(entity));有没有相关的危险。因为我遇到了这个错误,所以我更改了您的解决方案并且它有效。但我团队中的 Java 专家不太确定。
    • @BalusC em.remove(em.getReference(...)) 也可以吗?
    • @BalusC man.. 你是个天才。我遇到过同样的问题。但我将事务移至服务层并解决了我的问题。实际上我的情况有点不同,从 UI 我得到的只是用户的 ID,所以在我的服务中,我对数据库进行了 2 次调用。一是检查用户是否存在,二是删除。正如您所说,由于事务位于 DAO 层,因此它是一个单独的事务。所以我把它移到服务层并且它工作了..再次感谢你的清晰解释。
    【解决方案2】:

    就我而言,当我尝试删除一个对象时,我遇到了同样的错误 使用,

    session.delete(obj)
    

    在此之前不创建任何事务。

    而问题是通过先创建事务(session.beginTransaction()然后删除对象来解决的。

    我希望我的回答对某人有所帮助:)

    【讨论】:

      【解决方案3】:

      有时只是因为您缺少用于添加、删除、更新操作的 @Transaction 注释。

      【讨论】:

        【解决方案4】:

        我遇到了同样的问题。应重新连接分离的实体。正如@BalusC 提到的,应该使用EntityManager.merge() 来附加分离的实体。 EntityManager.merge() 生成 SQL 查询,该查询获取实体的当前状态,必须对其执行 EntityManager.remove()。但就我而言,它没有用。 请改用EntityManager.remove(EntityManager.find(Class&lt;T&gt;,arg))。它对我有用。

        【讨论】:

          【解决方案5】:

          根据我的经验,如果我从数据库中查询一个对象,然后关闭实体管理器,然后执行数据库删除,就会出现问题。或者,如果我将该加载的对象复制到另一个实例然后执行删除,也会发生此问题。 在我看来,有两点需要注意:

          • 对象必须在由实体管理器创建的同一会话中
          • 在实体管理器的会话仍处于打开状态时,不得将对象转移到另一个对象。

          干杯

          【讨论】:

            猜你喜欢
            • 2015-04-12
            • 2012-10-07
            • 1970-01-01
            • 1970-01-01
            • 2013-10-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-19
            相关资源
            最近更新 更多