MyBatis框架原理3:缓存

 上一篇[MyBatis框架原理2:SqlSession运行过程][1]介绍了MyBatis的工作流程,其中涉及到了MyBatis缓存的使用,首先回顾一下工作流程图:

如果开启了二级缓存,数据查询执行过程就是首先从二级缓存中查询,如果未命中则从一级缓存中查询,如果也未命中则从数据库中查询。MyBatis的一级和二级缓存都是基于Cache接口的实现,下面先来看看Cache接口和其各种实现类。

Cache接口及常用装饰器

public interface Cache {   String getId();   //缓存中添加数据,key为生成的CacheKey,value为查询结果   void putObject(Object key, Object value);   //查询   Object getObject(Object key);   //删除   Object removeObject(Object key);   //清空缓存   void clear();   //获取缓存数量   int getSize();   //获取读写锁   ReadWriteLock getReadWriteLock(); }

Cache接口位于MyBatis的cache包下,定义了缓存的基本方法,其实现类采用了装饰器模式,通过实现类的组装,可以实现操控缓存的功能。cache包结构如下:

  • PerpetualCache是Cache接口的实现类,通过内部的HashMap来对缓存进行基本的操作,通常配合装饰器类一起使用。
  • BlockingCache装饰器:保证只有一个线程到数据库中查询指定key的数据,如果该线程在BlockingCache中未查找到数据,就获取key对应的锁,阻塞其他查询这个key的线程,通过其内部ConcurrentHashMap来实现,源码如下:
public class BlockingCache implements Cache {    //阻塞时长   private long timeout;   private final Cache delegate;   //key和ReentrantLock对象一一对应   private final ConcurrentHashMap<Object, ReentrantLock> locks;    @Override   public Object getObject(Object key) {     //获取key的锁     acquireLock(key);     //根据key查询     Object value = delegate.getObject(key);     //如果命中缓存,释放锁,未命中则继续持有锁     if (value != null) {       releaseLock(key);     }             return value;   }  @Override   //从数据库获取结果后,将结果放入BlockingCache,然后释放锁   public void putObject(Object key, Object value) {     try {       delegate.putObject(key, value);     } finally {       releaseLock(key);     }   } ...
  • FifoCache装饰器: 先入先出规则删除最早的缓存,通过其内部的Deque实现。
  • LruCache装饰器: 删除最近使用最少的缓存, 通过内部的LinkedHashMap实现。
  • SynchronizedCache装饰器:同步Cache。
  • LoggingCache装饰器: 提供日志功能,记录和输出缓存命中率。
  • SerializedCache装饰器:序列化功能。

CacheKey

CacheKey对象是用来确认缓存项的唯一标识,由其内部ArrayList添加的所有对象来确认两个CacheKey是否相同,通常ArrayList内将添加MappedStatement的id,SQL语句,用户传递给SQL语句的参数以及查询结果集范围RowBounds等,CacheKey源码如下:

public class CacheKey implements Cloneable, Serializable { ...   private final int multiplier;   private int hashcode;   private long checksum;   private int count;   private List<Object> updateList;    public CacheKey() {     this.hashcode = DEFAULT_HASHCODE;     this.multiplier = DEFAULT_MULTIPLYER;     this.count = 0;     this.updateList = 
                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信