Hibernate save 在 session 中已存在相同 OID(主键) 的对象,会出现异常,详细内容如下:
Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.unmi.LoanDetail#1]
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:168)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at com.unmi.Test.main(Test.java:44)
重现以上错误的代码如下(去除了事物控制的代码行):
Session session = HibernateSessionFactory.getSession();
// 加载OID为1L的对象,会被放在session缓存中
LoanDetail detail = (LoanDetail)session.get(LoanDetail.class,1L);
// new 一个OID也为1L的临时对象
LoanDetail newDetail = new LoanDetail(1L);
ewDetail.setSubjectId(1000L);
// 持久化一个临时对象,试图放在session的缓存中,因OID冲突出现异常
session.save(newDetail);
// 执行saveOrUpdate同样会出现以上的异常
// session.saveOrUpdate(newDetail);
Session session = HibernateSessionFactory.getSession();
// 加载OID为1L的对象,会被放在session缓存中
LoanDetail detail = (LoanDetail)session.get(LoanDetail.class,1L);
// new 一个OID也为1L的临时对象
LoanDetail newDetail = new LoanDetail(1L);
newDetail.setSubjectId(1000L);
// 持久化一个临时对象,试图放在session的缓存中,因OID冲突出现异常
session.save(newDetail);
// 执行saveOrUpdate同样会出现以上的异常
// session.saveOrUpdate(newDetail);
解决方法:
1) 如果用的 hibernate 2, 需要在get/load/query到持久化对象,赋上新的属性值,再 save/update/saveOrupdate.
对以上代码就是:不能 new 一个session中已存在OID的对象,直接
detail.setSubjectId(1000L);
session.save(detail);
session.save()一个持久化对象时,会转化成update调用。
2) 使用 hibernate 3 的 merge 方法. session.merge(newDetail)即可,它会在 session 缓存中找到持久化对象,把新对象的属性赋过去,再保存原session中的持久化对象。
如果在session或数据库中没有的对象,用merge方法的话,它也能够帮你把记录 insert 到表中,相当于 save 方法。
上面是一个简单的例子,实际业务中可能是经过一番复杂的操作后自己也很难搞清楚 new 的一个新对象在 session/数据库中是否已存在。所以第一种方法你需要清楚你的每一个对象状态,第二种方法在 hibernate 3 中就比较通用一些。
附 hibernate javadoc 对 session.merge() 方法的注释:
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge".
分享到:
相关推荐
在使用Hibernate时,可能会遇到各种异常,如ConstraintViolationException(违反约束),NonUniqueObjectException(非唯一对象)等,理解并适当地处理这些异常是保证程序稳定运行的关键。 ### 8. 分页查询与批处理...
### Hibernate常见异常及解决方案 #### 一、保存了一个父对象,但是它的关联对象没有保存到数据库中 在Hibernate中,当我们保存一个实体时,如果该实体与其他实体有关联关系(如一对多或多对一),那么可能遇到的...
如Session接口提供了保存、更新、删除、加载和查询对象的方法。 3. **查询语言(HQL)**: Hibernate Query Language是一种面向对象的查询语言,类似于SQL,但更符合面向对象思维。 4. **Criteria查询**: 提供动态...
**Hibernate基础及应用详解** Hibernate 是一款开源的Java语言下的对象关系映射(ORM)框架,它极大地简化了数据库操作,使得开发者可以使用面向对象的方式来处理数据库事务,而无需过多关注底层SQL语句的编写。在...
- `save` 在保存对象的同时返回主键值,而 `persist` 不返回主键值。 - `save` 会在保存时立即执行 SQL 语句,而 `persist` 则会在 flush 或 commit 时才执行 SQL 语句。 2. **update** 与 **merge** - `update...
然而,在这种情况下,需要注意`org.hibernate.NonUniqueObjectException`异常的处理,该异常通常发生在同一个会话中试图保存具有相同标识符但不同对象的情况。例如: ```java public class ExampleServiceImpl { ...
- **Create(创建)**:通过Session的`save()`或`saveOrUpdate()`方法保存新对象到数据库。 - **Read(读取)**:`get()`或`load()`根据主键获取对象,`query()`或`criteria()`执行查询。 - **Update(更新)**:...
- **保存(Create)**:使用Session的save()或saveOrUpdate()方法保存对象到数据库。 - **读取(Read)**:通过Session的get()或load()方法获取对象,或使用Criteria或HQL(Hibernate Query Language)进行复杂查询...
- 对象的ID生成策略:例如,如果使用`<generator class="assigned" />`,Hibernate会在保存前检查数据库中是否存在相同ID的记录。 - Session的作用域:在一个Session中,对象的状态管理至关重要,同一对象的不同状态...
在应用配置中指定数据源、JPA供应商(如Hibernate)及相关的属性设置。 2.3 测试配置 编写测试代码验证JPA的配置是否生效,确保可以正常进行数据库操作。 2.4 环境搭建附表 列出完整的环境配置信息,如数据库连接...