之前写了一篇关于mybatis缓存的读后感,想了想还是把缓存模块简单分析一下,附赠下载地址:https://github.com/MyBatis/MyBatis-3,github直接搜排名很靠前的。
先看一张缓存源码包图片:
其实看到这个包,大致可以猜出decorators是装饰器,Cache是缓存的抽象,PerpetualCache类是缓存的具体实现,TransactionalCacheManager应该是关于事务的处理,带着这些猜测首先看下Cache类的源码实现:
可以看到里面都是关于缓存的增删改查操作以及读写锁的支持,但是都是抽象方法,接下来我们可以具体看下我们之前猜测的实现类PerpetualCache:
从红色框标注的看到确实是实现了cache接口的,实现的也很简单,只是使用了HashMap作为缓存容器,以及对map的基本操作。看到这里,是不是觉得这实现的也太简单了吧,而且,这个读写锁return null是什么鬼。我们首先来看是不是真的只是对hashMap的简单操作,回到最上面的图可以看到有一个cacheKey不知道是干什么的,先点进去看看里面写了啥:
进到代码里可以看到有几个核心的参数:
那么这些参数到底是怎么进行操作的呢,我们看一下里面核心的两个方法update和equals:
update方法其实就是通过计算hash值以及简单的运算更新参数,感兴趣的可以仔细研究测试一下,主要目的是为了减少key的冲突,equals则主要根据参数值的对比判断是否是同一个cacheKey,任意点开一个调用update方法的地方:
其实就是sql,节点id,分页信息以及参数信息,对多个值重复计算更新cachekey属性以尽量避免冲突,看到这我们是不是可以想到一个问题,只要nameSpace+分页+sql+参数都一样的话那就是同一个缓存值,哦,确实,都一样的话肯定是同一个。看到这里mybatis的缓存设计的是不是还是有点意思的,但是之前听说mybatis缓存模块设计的挺优雅的,就这样逼格还行但是也算不上优雅吧,我们发现还有一个包里面我们一个都没看过,打开decorators包发现里面都是实现了Cache接口的装饰器,这些装饰器的构造器都是需要传入一个缓存实现的,那么很明显,都是在最基础的PerpetualCache缓存基础上做的装饰而已。
BlockingCache:
首先看一下的get put方法:
可以看出其实就是阻塞版本的缓存装饰器,保证只有一个线程到数据库去查找指定的key对应的数据,而阻塞的实现就是使用可重入锁ReentrantLock控制并发。
FifoCache:
使用linkedList做先进先出的队列。
LoggingCache:
其实也就是在查询之后打印日志。
LruCache:
使用LinkedList实现热点访问。
ScheduledCache:
在每次读写时都会去删除过时的缓存,达到缓存的定时失效。
SerializedCache:
序列化缓存值,每次写入都会先进行序列化操作,读出都会反序列化。
SoftCache:
使用软引用存储缓存value值,若被垃圾回收器回收,则从容器中删除。
SynchronizedCache:
这个就很简单,加synchronized关键字,保证线程安全,这也是为什么二级缓存明明是跨sqlSession的,但是使用hashMap就可以保证线程安全。
TransactionalCache:添加事务处理。
WeakCache:和上面的软引用一样,只不过弱引用包装value值。
ps:软引用是表示垃圾回收器回收的时候,内存不够用才会回收,而弱引用在垃圾回收器回收的时候,无论什么状态,都会将对象回收。
上面其实就是mybatis缓存模块大致的运行机制与实现,还写了一篇文章简单聊了读完mybatis缓存源码,对缓存机制嗯大理解以及使用:https://www.cnblogs.com/gmt-hao/p/12317600.html欢迎大家指教。