本文讨论mybatis的二级缓存,在此之前,先讨论如何设计一个缓存:
- 存储方式。内存、磁盘或是其他。如果涉及到分布式,如何保证缓存一致性。
- 存储容量。缓存的总量需要是一定的,需要考虑淘汰算法。
- 过期时间。
- 线程安全。多线程访问你的缓存客户端是否是安全的。
- 命中率统计。可能用于缓存淘汰
- 序列化。
- 等等。
mybatis是如何实现二级缓存的呢(应用级缓存)?
顶层接口只有一个:Cache
/**
* @return The identifier of this cache
*/
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
上面讨论的缓存的各种能力如何基于该接口设计呢?mybatis采用的是装饰器 + 责任链的设计模式(待补充)
二级缓存不像是一级缓存只要写入后就可以立马使用,而是必须要先提交后,才可以进行使用。原因就是二级缓存是多线程的,它是跨会话的:就像数据库一样,不做限制会发生脏缓存的情况。
二级缓存的结构:
它比较像git,如果你熟悉git,你知道git的add操作只是将数据放到暂存区,提交的时候才会放到本地仓库。mybatis的二级缓存也是一样,只有提交了之后才会将数据放入缓存区(这里多个缓存区指的是多个Mapper,你可以为使用二级缓存的Mapper.xml或者是接口指明namespace,这样就是不同的缓存区了)
事务缓存管理器:TransactionalCacheManager
暂存区:TransactionalCache
二级缓存执行流程: