缓存数据被修改问题排查
五一之前同事和我说了一个奇怪的问题:项目中的一个资源模块版本a复制新增一个版本b之后,版本a在缓存中的数据变成了版本b的数据,缓存数据被修改了,导致之前版本a不能正常使用。
项目缓存设计
在分析这个之前,我研究了一下项目中缓存的设计,项目中模块有三个状态:草稿、预发布、已发布,我用一个流程图来演示草稿到预发布的过程:
问题分析
这次的问题出现在预发布版本a->草稿版本b
这个过程,由于版本a在由草稿变成预发布之后,缓存中的数据被删除了,后面在复制版本b的时候的时候需要查询版本a的数据,但是缓存中没有,所以去数据库查询数据(方法b)并放到缓存中,再基于查出来的数据对象,修改版本号之后创建草稿版本b。
几个注意点:
- 在预发布之后,草稿a的缓存被删除了
- 复制的时候去缓存查询了预发布版本a的数据,但是没查到,使用方法b去数据库查询,然后放入缓存
- 预发布版本a查出来的java对象,在直接修改之后,就去创建草稿版本b(这个时候其实把预发布版本a的缓存数据也修改了)
原因: 就是mybatis一级缓存导致的,一级缓存默认开启,在同一个sqlsession中,多次执行方法b查询数据库数据,第二次查询其实是查询的缓存数据,这就导致修改的是同一个java对象。
解决方案:
1、方法b查出来之后clone一个新的对象(由于查出来的对象数据都是基本数据类型,使用浅克隆没有影响)
2、在方法b对应的mybatis映射文件xml中,添加flushCache="true"
,这样在每次执行方法b都会去刷新缓存,查出来的java对象就不一样
我这里使用的第一种办法,影响范围较小,基本不会出来不可预知的错误