Mybatis缓存模块源码分析

Mybatis缓存模块源码分析

Mybatis中提供了缓存机制,而且有很多中不同策略的缓存,如LRU,FIFO,Schedule等等,那么Mybatis如何设计这些功能繁多的缓存呢?

1、装饰者模式设计缓存

1.1 提供统一的Cache接口:

public interface Cache {
    
    

  String getId();

  void putObject(Object key, Object value);

  Object getObject(Object key);

  Object removeObject(Object key);

  void clear();

  int getSize();

  default ReadWriteLock getReadWriteLock() {
    
    
    return null;
  }
}

1.2 提供一个最基本的实现,底层采用HashMap存储

/**
 * Cache最基本的实现,底层采用hashmap来实现
 * @author Clinton Begin
 */
public class PerpetualCache implements Cache {
    
    

  private final String id;

  private final Map<Object, Object> cache = new HashMap<>();
  // ....省略部分方法
 
  @Override
  public void putObject(Object key, Object value) {
    
    
    cache.put(key, value);
  }

  @Override
  public Object getObject(Object key) {
    
    
    return cache.get(key);
  }

  @Override
  public Object removeObject(Object key) {
    
    
    return cache.remove(key);
  }

  @Override
  public void clear() {
    
    
    cache.clear();
  }
}

1.3 其它功能的缓存,有LRU,FIFI,Blocking.等等,每个都提供了一个实现类,类中含有一个Cache对象,对这个Cache对象做增强,以FIFO为例:

/**
 * FIFO (first in, first out) cache decorator.
 *  采用LinkedList赋值实现,双端队列,队列中存储缓存的key,当容量满时,删除第一个key实现FIFO
 * @author Clinton Begin,
 */
public class FifoCache implements Cache {
    
    

  private final Cache delegate;
  private final Deque<Object> keyList;
  private int size;

  public FifoCache(Cache delegate) {
    
    
    this.delegate = delegate;
    this.keyList = new LinkedList<>();
    this.size = 1024;
  }

  @Override
  public void putObject(Object key, Object value) {
    
    
    cycleKeyList(key);
    delegate.putObject(key, value);
  }

  @Override
  public Object getObject(Object key) {
    
    
    return delegate.getObject(key);
  }

  @Override
  public Object removeObject(Object key) {
    
    
    return delegate.removeObject(key);
  }

  @Override
  public void clear() {
    
    
    delegate.clear();
    keyList.clear();
  }
 // 容量满时,移除最早的
  private void cycleKeyList(Object key) {
    
    
    keyList.addLast(key);
    if (keyList.size() > size) {
    
    
      Object oldestKey = keyList.removeFirst();
      delegate.removeObject(oldestKey);
    }
  }

}

2、BlockingCache经典代码分析

private final ConcurrentHashMap<Object, ReentrantLock> locks; 

// 解决缓存雪崩问题
  @Override
  public Object getObject(Object key) {
    
    
    acquireLock(key);
    Object value = delegate.getObject(key);
    if (value !=  null) {
    
    
      releaseLock(key);
    }
    return value;
  }

BlockingCache中有这段代码,可以保证当发生缓存雪崩(缓存中没有数据,需要去数据库中查),在一个高并发系统中,如果不进行控制,第一批请求全部涌入数据库,很可能造成数据库挂掉。有的解决方案也是加锁,但是把缓存作为锁,这样的话锁粒度过大,并发量不高。但这里采取每个key一把锁,大大降低了锁的粒度。

猜你喜欢

转载自blog.csdn.net/weixin_43213517/article/details/106590290