1、一级缓存问题
一级缓存:存在于单个会话之中,当会话提交或者关闭,会清空缓存,缓存数据存在会话中的executor的localcache中,缓存sql的数据被修改也会清空缓存,但当我们使用分布式部署时,每个机器上的每个会话独享自己的缓存,且每个机器无法共享一级缓存上数据是否被修改,这就导致一种情况,A,B服务器上A、B会话之前都缓存了某条数据,现在A服务上修改了该条数据,A服务A会话的缓存被清空了,但B服务器的B会话的缓存仍然是之前的数据,不知道该数据已经被更改,导致在B服务器上执行的脏读。
1、1 解决办法
调整一级缓存的作用范围,设置 LocalCache 级别为 statement 或者在语句上设置 flushCache=“true” 都可以。目的就是使一级缓存失效。
2、二级缓存问题
跨会话的,开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查询,二级缓存没找到再去一级缓存找,一级缓存也没有就直接查数据库;
但二级缓存对于多表查询容易产生脏读,因为他的缓存是基于namaspace的,如果跨越了namespace其他命名空间去修改了数据,我们是监测不到的,就导致当前的命名空间查询出来的缓存数据是存在问题的;
分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,可以通过Cache接口实现,但那玩意想想都复杂,成本太大,不如直接用分布式的redis做数据缓存;
3、总结
一级缓存用处不大,默认开启,分布式下不能使用;
二级缓存使用联表查询可能出问题,条件比较苛刻,所以还是不用比较好;但如果对数据一致要求不是那么高,倒也无所谓了;
单体架构推荐spring提供的ehcache做数据缓存;
分布式架构直接使用redis做数据缓存;