save与 merge与 saveOrUpdate的区别

本文详细解析了ORM中save(), update(), saveOrUpdate()等方法的区别及应用场景,帮助开发者更好地理解和使用这些核心方法。

save()方法很显然是执行保存操作的,如果是对一个新的刚new出来的对象进行保存,自然要使用这个方法了,数据库中没有这个对象。

update()如果是对一个已经存在的托管对象进行更新那么肯定是要使用update()方法了,数据中有这个对象。

saveOrUpdate()这个方法是更新或者插入,有主键就执行更新,如果没有主键就执行插入。

区别:对于一个从托管状态到瞬态的对象(对于一个从数据库中取出来又被删除的对象),这个对象本身是有主键的,但是因为被删除了,

所以这个时候因为数据库中已经没有了这条记录了。不过它还有主键存在,所以这个时候不可以使用update()或者是saveOrUpdate(),

因为update()方法是认为数据库中肯定有这条记录的,而saveOrUpdate的执行过程就是先查看这个对象是不是有主键,有主键那么就执行

update()方法,没有主键就执行save()方法,因此结果跟调用了update()方法的效果是一样的,结果就会出错,因为这个对象已经被删除了,

数据库中已经没有这条记录了,只是它还有主键而已(仅仅是存在于内存中),因此这个时候要执行的是save()方法。

**********************************************************************************************

一、save()和persist()将会引发SQL的INSERT,delete()会引发SQLDELETE,
而update()或merge()会引发SQL UPDATE。对持久化(persistent)实例的修改在刷新提交的时候会被检测到,它也会引起SQL UPDATE。
saveOrUpdate()或者replicate()会引发SQLINSERT或者UPDATE
二、save 和update区别
把这一对放在第一位的原因是因为这一对是最常用的。
save的作用是把一个新的对象保存
update是把一个脱管状态的对象或自由态对象(一定要和一个记录对应)更新到数据库

三、update 和saveOrUpdate区别
这个是比较好理解的,顾名思义,saveOrUpdate基本上就是合成了save和update,而update只是update;引用hibernate reference中的一段话来解释他们的使用场合和区别
通常下面的场景会使用update()或saveOrUpdate():
程序在第一个session中加载对象,接着把session关闭
该对象被传递到表现层
对象发生了一些改动
该对象被返回到业务逻辑层最终到持久层
程序创建第二session调用第二个session的update()方法持久这些改动

********************************************************************************************************************

 

转载于:https://www.cnblogs.com/ainiaiwo/p/5826681.html

### 解析 `saveOrUpdate` 方法报错的原因 在 Hibernate 中,`saveOrUpdate` 方法的行为取决于实体对象的状态及其 ID 是否为空。如果 ID 不为 null,则尝试执行更新操作;反之则执行保存操作。然而,在某些特定场景下,这种方法可能导致异常。 #### 异常分析 当遇到如下异常: ```plaintext org.springframework.orm.hibernate5.HibernateOptimisticLockingFailureException:Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; ``` 这表明 Hibernate 尝试对数据库中的记录进行更新时未能找到匹配的数据行[^1]。具体来说,可能是由于传入的对象并未真正存在于数据库中或者其版本号不一致所引起的乐观锁失败。 #### 可能的原因 - **ID 配置错误**:若对象的 ID 字段未被正确设置或配置不当,可能会使 Hibernate 错误判断该实例应作为新记录还是现有记录处理。 - **并发修改冲突**:多个事务同时访问并试图更改同一数据项也可能引发此类问题,尤其是在启用了乐观锁定机制的情况下。 - **脏读/幻读现象**:应用程序可能基于过期缓存或其他方式获取到了陈旧状态的信息,并据此构建待持久化的对象实例。 - **映射关系复杂度高**:如关联集合(一对多、多对多等)管理不当也会造成意想不到的结果,特别是当涉及级联操作时[^2]。 ### 推荐解决方案 针对上述情况,建议采取以下措施之一解决问题: #### 方案一:替换为更合适的 API 调用 考虑使用更为精确的方法代替 `saveOrUpdate()` ,例如: - 对于新增加的数据条目显式调用 `session.save(entity)`; - 更新已有记录时采用 `session.update(entity)` 或者 `session.merge(entity)` 来确保能够适当地反映最新的业务逻辑需求[^4]。 这样做的好处是可以更好地控制程序行为,减少不确定因素带来的风险。 #### 方案二:优化现有代码结构 仔细审查当前实现细节,确认是否有必要继续沿用 `saveOrUpdate()` 。如果是的话,请务必保证传递给它的参数始终处于有效范围内——即要么确实代表一个新的实体实例(此时 ID 应设为 null),要么确切对应着某个已存在的数据库记录(需提供有效的主键值)。此外还需注意保持良好的编程习惯,比如及时清理不再使用的临时变量以及合理运用懒加载特性等等。 #### 方案三:增强测试覆盖率 通过编写单元测试案例覆盖各种边界条件下的输入组合,提前捕捉潜在缺陷所在之处。对于那些难以重现的问题尤其重要的是模拟真实的运行环境来进行压力测试和性能评估工作。 ```java // 示例代码片段展示如何安全地使用 session.save() public void safeSave(Entity entity){ Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); if (entity.getId() == null || !existsInDatabase(entity)) { // 检查是否存在 session.save(entity); } else { session.update(entity); // 显式指定更新而非依赖 saveOrUpdate } tx.commit(); } catch (RuntimeException e) { if (tx != null && tx.isActive()) { tx.rollback(); // 发生异常回滚交易 } throw e; } finally { session.close(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值