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

相关推荐
文艺理科生9 分钟前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling9 分钟前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
南极企鹅11 分钟前
springBoot项目有几个端口
java·spring boot·后端
Luke君6079713 分钟前
Spring Flux方法总结
后端
define952717 分钟前
高版本 MySQL 驱动的 DNS 陷阱
后端
清风拂山岗 明月照大江17 分钟前
Redis笔记汇总
java·redis·缓存
xiaoxue..32 分钟前
合并两个升序链表 与 合并k个升序链表
java·javascript·数据结构·链表·面试
忧郁的Mr.Li1 小时前
SpringBoot中实现多数据源配置
java·spring boot·后端
yq1982043011561 小时前
静思书屋:基于Java Web技术栈构建高性能图书信息平台实践
java·开发语言·前端
一个public的class1 小时前
你在浏览器输入一个网址,到底发生了什么?
java·开发语言·javascript