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

相关推荐
多多*3 分钟前
一个有 IP 的服务端监听了某个端口,那么他的 TCP 最大链接数是多少
java·开发语言·网络·网络协议·tcp/ip·缓存·mybatis
Kay_Liang9 分钟前
Spring IOC核心原理与实战技巧
java·开发语言·spring boot·spring·ioc·依赖注入·控制反转
Mr.wangh30 分钟前
单例模式&阻塞队列详解
java·开发语言·单例模式·多线程·阻塞队列
查老师34 分钟前
就为这一个简单的 Bug,我搭上了整整一个工作日
后端·程序员
Slow菜鸟40 分钟前
Java后端常用技术选型 |(三)分布式篇
java·分布式
q***99444 分钟前
Spring Boot 实战:轻松实现文件上传与下载功能
java·数据库·spring boot
张较瘦_1 小时前
[论文阅读] 软件工程 | 解决Java项目痛点:DepUpdater如何平衡依赖升级的“快”与“稳”
java·开发语言·论文阅读
老华带你飞1 小时前
记录生活系统|记录美好|健康管理|基于java+Android+微信小程序的记录生活系统设计与实现(源码+数据库+文档)
android·java·数据库·vue.js·生活·毕设·记录生活系统
绝无仅有1 小时前
大厂某里电商平台的面试及技术问题解析
后端·面试·架构
天若有情6731 小时前
从零实现轻量级C++ Web框架:SimpleHttpServer入门指南
开发语言·前端·c++·后端·mvc·web应用