Mybatis一级缓存导致分布式环境下的查询脏数据

    Mybatis一级缓存,也称本地缓存,默认是SqlSession级别的缓存。在一次程序与数据库的会话(Sqlsession)中,mybatis会维护一个以hashmap为存储结构的一级缓存,在这个会话中,只要在两次相同条件的查询中间,这个会话里没有出现增删改的操作,那么Mybatis会在第二次查询时候在缓存中将这个结果返回,导致两次查询的返回结果对象其实是一个,用“==”比较结果为true。

    Mybatis的一级缓存是默认开启的,且截至目前我们无法关闭。当一级缓存默认是SqlSession级别时,其生命周期和其所在的Sqlsession相同。而且,Mybatis的一级缓存使用了hashMap,且没有做容量上的限定。

    在分布式环境下,Mybatis的一级缓存无法集中统一管理,也就是说Mybatis无法搭建分布式缓存。在多个SqlSession环境下,虽然可以使用二级缓存,即全局缓存,以在多个SqlSession共享缓存,但是毕竟是本地存储,还是无法适应分布式的需求。所以为了避免在分布式环境下的脏数据读取,解决方法有两个,一是可以设置Mybatis一级缓存为STATEMENT级别,因为在查询方法执行的最后,会判断一级缓存级别是否是STATEMENT级别,如果是的话,就清空缓存。如此一来,便相当于不使用一级缓存。在select标签里面设置flushCache="true"即可,也可以如图2配置成全局,但是后面这种方式在一些版本中并不支持。在自己创建SqlSession的时候,每次查询完毕后调用SqlSession类的clearCache()方法也可以清空缓存。

    二是使用EnChache等分布式缓存框架,搭建分布式缓存。 

 

Psby2018/7/26 10:17 : 作者亲测,在Spring boot+Mybatis某些版本之后,就没有这个问题了,可能是每次访问Mapper都会创建新的SqlSession,当然只是可能。反正如果是Spring boot环境,可以在配置文件中加入

logging.level.com.example.demo.test.dao.userMapper=debug

com.example.demo.test.dao.userMapper是你的dao接口名字。作者在这里忘记大写首字母了,见怪勿怪。。。

如果是Spring 环境,在mybatis-config文件中的configuration根节点加入

<settings>
   <!-- 打印查询语句 -->
   <setting name="logImpl" value="STDOUT_LOGGING" />
</settings>

,就可以在控制台查看程序是否执行了Sql语句了,从而判断是否会出现脏数据读取问题。

    关于MyBatis的好的文章:

https://www.jianshu.com/p/c553169c5921

 

展开阅读全文

没有更多推荐了,返回首页