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还是会对缓存中的数据进行同步到数据库操作。

相关推荐
CoderYanger1 分钟前
A.每日一题——2141.同时运行N台电脑的最长时间
java·算法·leetcode·职场和发展·1024程序员节
旺仔Sec2 分钟前
2025年广东省职业院校技能大赛应用软件系统开发赛项(高职组)赛题(一)
java·应用软件系统开发
小周在成长7 分钟前
Java 匿名内部类简明指南(重点)
后端
雨中飘荡的记忆7 分钟前
Spring AI + Redis 向量库实战
java·redis·spring
CC.GG10 分钟前
【C++】面向对象三大特性之一——继承
java·数据库·c++
零匠学堂202512 分钟前
woapi-server为Office Online Server文档在线预览提供文档加载地址
java·运维·服务器·oos·wopi
Hui Baby14 分钟前
maven自动构建到镜像仓库
java·maven
郑州光合科技余经理14 分钟前
技术架构:跑腿配送系统海外版源码全解析
java·开发语言·前端·数据库·架构·uni-app·php
czlczl2002092520 分钟前
SpringBoot手动配置:WebMvcConfigurer接口实现类的生效原理
java·spring boot·后端
程序员皮皮林21 分钟前
SpringBoot + nmap4j 获取端口信息
java·spring boot·后端