五一之前同事和我说了一个奇怪的问题:项目中的一个资源模块版本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对象就不一样

我这里使用的第一种办法,影响范围较小,基本不会出来不可预知的错误

标签: Mybatis

添加新评论