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

Posted

技术标签:

【中文标题】java.lang.IllegalArgumentException:删除分离的实例 com.test.User#5【英文标题】:java.lang.IllegalArgumentException: Removing a detached instance 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

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

【问题讨论】:

【参考方案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】:

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

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

干杯

【讨论】:

以上是关于java.lang.IllegalArgumentException:删除分离的实例 com.test.User#5的主要内容,如果未能解决你的问题,请参考以下文章

IllegalArgumentException:此 NavController 未知导航目的地 xxx