mybatis的一二级缓存原理

先了解这个储备点:

缓存的顶层接接口:Cache接口,里面定了对缓存的基本操作。具体实现类有BlockingCache,LruCache,SerializedCache,FifoCache等等。我们这里只了解PerpetualCache。

PerpetualCache里持有一个hashMap,对缓存的操作其实就是对这个map的操作。

一级缓存实现原理:

一级缓存是sqlSession级别的缓存,默认是开启的。如果需要关闭一级缓存,需要在mybatis-config.xml中配置。

原理:

mybatis的一级缓存是在Executor中进行维护的。为什么?猜一下吧,因为一级缓存是sqlSession级别的缓存,所以我们来看sqlSession的唯一实现类DefaultSqlSession。DefaultSqlSession中有五个属性:autoCommit(是否自动提交),dirty(标识位),cursorList(存放游标相关信息),configuration(全局配置信息,也不适合作为一级缓存),只有Executor最有可能。然后联想到sqlSession执行的时候,实际上就是交给Exector去执行,所以Executor比较适合用来存储存储。

所以,来看Executor的实现类BaseExecutor,内部果然持有一个PerpetualCache属性对象。这个对象里面其实就是有一个hashashMap,上面也说了。

那么,既然是缓存,那么缓存的key是如何生成的?答:主要分为6步。

接下来,看看 BaseExecutor的query方法,看看是如何使用一级缓存的?

答:query方法的具体逻辑:缓存有查缓存,缓存没有查库再放入一级缓存。而且这里还有个逻辑:从Configuration中拿值看一级缓存是否关闭,如果关闭,则直接清除一级缓存。

再来说一下一级缓存的清除:以BaseExecutor的update方法为例:

可知:在执行update,commit,和rollback的时候都会清除一级缓存。

二级缓存实现原理:

二级缓存是Mapper级别的缓存,因此不同的sqlSession间可以共享缓存。二级缓存是默认开启的,可以在全局配置文件中配置。

二级缓存使用了包装成的CachingExecutor。在哪里包装的呢?在BaseExecutor的newExecutor中有这样的判断逻辑。看看这里面的CachingExecutor类的源码吧:

里面有两个成员变量,其中一个就是TransactionCacheManager,只是用来管理缓冲的。ransactionCacheManager内部也维护了一个hashmap。看一下具体的缓存类吧:TansactionCache:这里面其实有一个entriesToAddOnCommit的临时中间变量,是为了解决sqlSession之间的脏读问题(脏读问题解释:A线程修改了数据,B线程去查询,如果此时A回滚了后,那么缓存中维护的就是一个脏数据)。

接下来,看看二级缓存是如何工作的:

以CachingExecutor的query方法为例:也是执行增删改的时候会清空二级缓存,这里假如从一级缓存中查到数据后,先要放到entriesToAddOnCommit临时变量中,等真正commit的时候再保存到真正的缓存中。如果没有配置二级缓存,则执行普通查询。

你可能感兴趣的:(mybatis,缓存,java)