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一把鎖,大大降低了鎖的粒度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章