问题描述:
场景需求:主方法中“方法1”先更新一条数据(带有事务),更新成功后,希望能在“方法2”查询到事务提交后的数据,再做其他的逻辑处理。
先前处理方式:在一个未开启事务的方法中,调用一个带有事务的方法,接着查询事务提交后的最新数据。
结果:事务提交成功,接着jpa sql查询,发现出来的数据还是事务提交前的数据;接着去观察数据库是否已经commit最新的数据,发现数据库上确实是已经查询出代码已经提交的数据。
排查描述:
1、一开始认为是事务的问题,同一个事务中,如果提交了数据在同一个事务中查询是不能查询到最新的结果。此时业务代码处理逻辑并不是在同一个事务中;
2、观察数据库上最新的记录,发现“方法1”事务提交后,在数据库中能查询到最新的提交数据;
3、数据库没问题,只能说明在代码层中会存在缓存问题,当查询的时候,如果缓存中匹配条件,可能就会返回事先存放在缓存中的那条数据;
4、带着缓存问题查询,发现EntityManager自身就是一种缓存。事务中从数据库获取的和写入到数据库的数据会被缓存。在一个程序中也许会有很多个不同的EntityManager实例,每一个实例运行着不同的事务,拥有着它们自己的缓存。那么当EntityManager需要通过主键或者关联关系获取一个实体对象时,它首先会去缓存中寻找。如果找到了,那么它就不需要对数据库进行访问了。
解决方法:
1、在每一个Dao中继承的JpaRepository,发现里面有一个flush()方法,尝试着在更新后调用该方法刷新结果集,发现再次查询出来的数据还是之前缓存的数据;
2、在XXDao层的update语句上面,通过注解方法刷新缓存;
3、再次执行,发现事务提交后的数据,jpa查询能获取到最新的记录。