org.hibernate.NonUniqueObjectException:a different object with the same identifier value was alread

本文详细解析了在使用Hibernate框架时遇到的NonUniqueObjectException异常,主要原因是同一session中存在相同主键的多个对象。文章提供了三种解决方案:使用已加载的对象进行修改、使用merge方法或evict对象使其成为脱管状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:……


        主键不唯一,在事务的最后执行SQL时,session缓存里面有多个(>1)主键一样的对象
 

原因:了解过hibernate的都知道它有一个一级缓存,即session级别的缓存,在一个事务的执行过程中可以管理持久化对象,在事务最后执行SQL,可以减少数据库的操作。


可能的场景:

1、同一个object,如一个person在seession里保存了一份,而增加的别的object,如company的时候,由于做了关联关系,从数据库里又get了一个person,而这个person和seession里的person是同一个,把get出来的person   set 到了company里,像这样,compnay.setPerson(person).在增加company的时候就出现了这个错误。

2、在同一个session内,如果已经有一个对象已经是持久化状态(load进来等),现在构造一个新的PO,和前一个持久化对象拥有相同的持久化标识(identifier),在update的时候,就会抛这个错误。如:
 

User user1 = session.load(1);
User user2 = new User();
user2.setId(1);//此时ID和user1一样
user2.setUsername("lalala");
session.update(user2);//这里会抛出错误

解决办法:

1.不要重新new一个对象,使用load的对象对他进行更改值。
例如上面例子直接对user1操作,最后更新user1
2.如果是hibernate3以上,可以使用session.merge()方法
3.把session中同标识的对象移出(session.evict(user1)),使他成为脱管的状态,然后user2就可以update了。


 

<think>我们遇到了Hibernate的异常:一个具有相同标识符值的不同对象已经与会话关联。这通常发生在尝试将一个已经与当前Hibernate会话关联的对象(具有相同ID)再次关联时。 常见场景: 1. 在同一个session中,尝试加载两个相同ID的对象。 2. 在未清理session的情况下,重复保存或更新同一个对象。 解决方法: 1. 使用`session.merge()`代替`session.saveOrUpdate()`或`session.update()`,因为`merge()`会返回一个托管状态的持久化对象,而不会改变原有对象的状态。 2. 确保在同一个session中,对于同一个数据库行,只有一个对象表示。 3. 检查是否在同一个事务中多次加载了同一个实体(例如通过两个不同的查询),如果是,确保只使用一个实体实例。 4. 使用`session.evict()`将旧对象session中清除,然后再保存新对象(但需谨慎,以免丢失未提交的更改)。 5. 使用Hibernate的`session.clear()`清除整个session(在批量操作时有时会这样做,但要注意清除后之前加载的对象都变为脱管状态)。 示例代码(使用merge): ```java MyObject obj = new MyObject(); obj.setId(8); // 设置其他属性... MyObject managedObj = session.merge(obj); ``` 或者,如果你已经有一个对象session中,然后你又创建了一个具有相同ID的新对象,你应该避免这样做,而是从session中获取已存在的对象并更新它。 另一种情况:在循环中处理对象时,如果没有清空session,可能会导致大量对象驻留内存,最终可能引发此异常。此时可以考虑定期清空session(flush and clear)。 具体问题需要具体分析,但核心是:确保在同一个Hibernate Session中,对于同一个数据库行(同一个ID),只有一个实体对象。 现在,根据要求,在最后提出3-5个相关问题。</think>### 关于 Hibernate 异常 "a different object with the same identifier value was already associated with the session" 的解释 这个异常发生在 Hibernate 会话(Session)中尝试关联两个不同对象但具有相同数据库标识符(ID)的情况。在您遇到的错误中,ID 为 8 的对象出现了冲突。 #### 根本原因: 1. **会话中已存在相同 ID 的对象** 当会话中已存在 ID=8 的实体对象时,尝试添加另一个 ID=8 的新对象会导致冲突 2. **常见场景**: ```java // 场景1:从会话获取对象后,又创建新对象 Order order1 = session.get(Order.class, 8); // 对象已关联会话 Order order2 = new Order(8, ...); // 新建相同ID对象 session.save(order2); // 抛出异常! // 场景2:未正确使用 merge() Order detachedOrder = new Order(8, ...); // 脱管对象 session.update(detachedOrder); // 错误用法 ``` #### 解决方案: 1. **正确使用 `merge()` 替代 `save()/update()`** ```java Order newOrder = new Order(8, ...); // 新建对象 Order managedOrder = session.merge(newOrder); // ✅ 正确做法 ``` 2. **检查对象来源** 确保操作的是同一个对象实例: ```java Order order = session.get(Order.class, 8); order.setStatus("SHIPPED"); // 直接修改已关联对象 // 无需再次保存 ``` 3. **清除会话状态(必要时)** ```java session.evict(existingOrder); // 从会话移除旧对象 session.save(newOrder); // 再保存新对象 ``` 4. **检查级联操作** 确认关联实体(如 `@OneToMany`)没有重复创建相同ID的子对象 #### 预防措施: ```java // 在保存前检查会话是否已存在该ID if (session.contains(existingObj)) { session.evict(existingObj); } session.save(newObj); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值