Hibernate持久化对象与事务的坑

今天排查项目Bug时发现了一个问题,有一个数据库的记录被莫名其妙更新了,查看了相关的业务代码,并没有发现有任何的save保存方法被调用

java 复制代码
ActionEntity byActionId= actionEntityRepository.findAllByActionId(actionId);
byActionId.setActionNumberScript(NumberUtils.toInt(personalizationSolutionsEntity.getActionNumber());
byActionId.setActionGroupScript(NumberUtils.toInt(personalizationSolutionsEntity.getActionGroupNumber());
byActionId.setActionDuration(personalizationSolutionsEntity.getActionDuration());

如以上(简洁)代码所示,仅仅是查出了这个对象,set了一些属性,并没有调用save方法进行更新,但是最后结果还是数据库被更新了,经过排查后,确定是Hibernate机制的问题,如果修改了经过Hibernate框架查出的对象,并且加了非只读事务管理,那么Hibernate会在事务提交的时候自动更新数据到数据库无论你是否调用save方法

先说解决办法

  1. 去掉事务(大多数情况下不太可行)

  2. 对不需要同步数据库的对象,查出后直接new一个新对象,复制属性替代原对象进行操作即可

Hibernate 对象状态

凡是经过 Hibernate 框架查出的对象,统一是持久化状态,持久化状态的对象会被关联存储在Hibernate SqlSession 的缓存中,在之后对这个对象任何的修改都会被记录到缓存里去,当然正常情况下你不调用 save 方法,这些缓存并不会同步到数据库中去,但是重点来了,如果你在方法上添加了@transactional 注解,那么Hibernate会自动在事务提交的时候将缓存中的数据同步到数据库中。

解决办法的第二种new一个新对象,这个对象的状态就是脱管,不归属于Hibernate管理,所以不会出现缓存自动同步问题

Hibernate 缓存与事务关系

如果你指定的事务是只读事务,

java 复制代码
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)

那么Hibernate并不会对数据库进行修改,因为这个注解告诉它只需要读取,无需写入

但是如果你使用了多层事务,也就是说最外层是只读事务,但是内层嵌套了普通事务,那么Hibernate还是会对缓存中的数据进行同步到数据库操作。

相关推荐
王码码203516 分钟前
Go语言CGO:Go与C交互
后端·golang·go·接口
XiaoYu1__18 分钟前
JavaGUI文件管理系统开发实战:从静态展示到动态交互的演进
java·开发语言
霸道流氓气质27 分钟前
MCP(Model Context Protocol)核心概念与Java SDK集成
java·开发语言
PC2005-cloud1 小时前
DSH 白嫖指南:接入 Command Code Go、WorkBuddy 与 Trae 的免费额度
开发语言·后端·golang
敲代码的嘎仔1 小时前
从集群锁失效到异步领券:我用分布式锁 + Redisson + MQ 把领券接口 RT 从 200ms 压到 15ms
java·数据库·redis·分布式·缓存·ai·wpf
步行cgn1 小时前
Spring 的模块体系详解
java·数据库·spring
xcl09251 小时前
智慧健身场馆系统开发实战:从架构设计到核心模块落地指南
java·spring boot
vx-程序开发1 小时前
【计算机毕设】基于Spring Boot的古城景区管理系统88564
java·数据库·spring boot·后端·spring·elasticsearch·课程设计
鹿角片ljp1 小时前
LeetCode 31:下一个排列|右找小,右找大,交换,右反转
java·数据结构·算法
边境悍匪1 小时前
蜗牛学苑 Java 智能体学习 Day40|Vue 工程化与 ElementPlus 思维导图复盘
java·vue.js·学习