困扰了我将近一周的诡异bug!

现象:

整个项目没有插入数据库该表的数据的代码,诡异的增加数据。
后来和使用该项目的同事一起分析总结规律,好像都是页面查询显示时会触发数据库update,于是Mysql中加入了binlog和general_log。

一番苦等,两天之后,终于同事发现不断使用页面查询后,过几分钟,诡异重现!!!数据不断变化,于是查看bin-log(或general_log)发现居然有update语句出现,而且最初发生update的开始时间与同事执行的查询时间中某一条数据的时间一致,秒都没差。于是开始在同事大概访问的几个页面中排查后端java代码。在其中找到了对List中所有对象逐个"set(值***)"的方法,修改了所有对象的值。这个是初步断定最能直接影响数据的地方了。果不其然,网上一查关键字“springboot的set方法修改数据库”,大神出现了!!

。。。一顿操作(见横线下面转载原文)。。。解决!!!

最后记得及时关闭general_log,太浪费磁盘空间了。
bin-log可以不用关,默认最大占用1G,之后自动滚动更新。


下面是转载的原文,对有补充说明。


项目进行了三分之二了,突然出现一个很诡异的bug,数据库存储的用户表中密码信息总是自动消失一部分,头疼了几天后突然想起同事有个对低权限用户查询的用户信息向前台传送时会把密码设成null后再传输,心想是不是这个原因,毕竟就密码消失了。

仔细一查看,我还真调用了他的那个方法,就是那个set方法把对象密码清空的同时也更了数据库,因为第一次接触JPA项目,有点不明觉厉,请教了公司前辈大牛,给出了解决方法。

Springboot Jpa 的自动事务托管中,当session中的缓存对象数据行有改变时(set赋值后)与数据库数据不一致,这时候同步锁就会去flush数据库的对应行数据,让其和session中对象的数据相同。

1. 首先引入EntityManager:

springboot 更新 bean springboot 更新数据如何防止被改_自动更新

2. 然后,用它来强转获得HibernateEntityManager,然后调用获得Session,然后在set完之后(注意是之后,不是之前)用Session的.evict()方法,清掉对象缓存(并非所有对象缓存),如此就ok了...

springboot 更新 bean springboot 更新数据如何防止被改_springboot 更新 bean_02

重点:

好吧,已经java11不建议用HibernateEntityManager了,不过还能用,可以先用着,不过推荐如下新的获取Session的方法,版本高的可以用新方法:

springboot 更新 bean springboot 更新数据如何防止被改_jpa_03

补充:

如果你是obj,你就直接用session.evict(obj);直接擦除即可。

我这里是List装的set数据,不能直接evict List会抛异常报错,要把里面的obj逐个传进去擦除才行,所以要用到for循环了。