Mybatis源碼分析-二級緩存

二級緩存和一級緩存不一樣的地方在於,二級緩存針對的是MapperStament,比一級緩存更細!
首先在使用一級緩存之前,mapper.xml文件中要配置標籤來開啓二級緩存,而且可以細化到mapper.xml中的每條sql語句,比如

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>
  <select ... flushCache="false" useCache="true"/>

這個更高級的配置創建了一個 FIFO 緩存,並每隔 60 秒刷新,存數結果對象或列表的 512 個引用,而且返回的對象被認爲是隻讀的,因此在不同線程中的調用者之間修改它們會 導致衝突。

可用的收回策略有:

LRU – 最近最少使用的:移除最長時間不被使用的對象。
FIFO – 先進先出:按對象進入緩存的順序來移除它們。
SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
默認的是 LRU。

flushInterval(刷新間隔)可以被設置爲任意的正整數,而且它們代表一個合理的毫秒 形式的時間段。默認情況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新。

size(引用數目)可以被設置爲任意正整數,要記住你緩存的對象數目和你運行環境的 可用內存資源數目。默認值是 1024。

readOnly(只讀)屬性可以被設置爲 true 或 false。只讀的緩存會給所有調用者返回緩 存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優勢。可讀寫的緩存 會返回緩存對象的拷貝(通過序列化) 。這會慢一些,但是安全,因此默認是 false。

先來看
下配置階段的解析mapper.xml文件中的一段代碼

  public Cache useNewCache(Class<? extends Cache> typeClass,
      Class<? extends Cache> evictionClass,
      Long flushInterval,
      Integer size,
      boolean readWrite,
      boolean blocking,
      Properties props) {
    Cache cache = new CacheBuilder(currentNamespace)
        .implementation(valueOrDefault(typeClass, PerpetualCache.class))
        .addDecorator(valueOrDefault(evictionClass, LruCache.class))
        .clearInterval(flushInterval)
        .size(size)
        .readWrite(readWrite)
        .blocking(blocking)
        .properties(props)
        .build();
        //將生成好的緩存存儲於MapperBuilder和Configuration中,當然此時緩存中時沒有數據的,這裏又用到了裝飾模式進行功能增強,而且套了好幾層
    configuration.addCache(cache);
    currentCache = cache;
    return cache;
  }

那麼 最終會根據各自配置的緩存放至到對應的MapperStatement中,也就是說每個mapper都對應有一個自己的緩存,是不是比一級緩存更細了!
好了

 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
      //獲取緩存對象,看是否開啓狀態
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);
      //判斷是否使用緩存
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        //獲取緩存數據
        List<E> list = (List<E>) tcm.getObject(cache, key);
       //爲空?
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          //將獲得的數據進入緩存
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //繼續query 在這裏會從一級緩存或者數據庫獲取數據
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

上面可以看出,先後順序是先二級緩存>一級緩存>數據庫獲取
我們具體看看一級緩存的內容
先來看下Cache接口

public interface Cache {

 //唯一標示
  String getId();
//插入
  void putObject(Object key, Object value);
  //獲取
  Object getObject(Object key);

//移除
  Object removeObject(Object key);
//清空
  void clear();
//個數
  int getSize();
//讀寫鎖
  ReadWriteLock getReadWriteLock();

}

這裏寫圖片描述
哦,好多裝飾類,其實都是簡單的
這裏寫圖片描述
BlockingCache:增加 可阻塞功能,會在查詢緩存時鎖住對應的Key,如果緩存命中了則會釋放對應的鎖,否則會在查詢數據庫以後再釋放鎖,這樣可以阻止併發情況下多個線程同時查詢數據
FifoCache:增加fifo功能,即先進先出功能-根據固定的長度,默認爲1204 ,如果超出則將第一個移除,在新增
LoggingCache : 增加日誌功能-調用方法先日誌
LruCache:增加lru功能及最近最少使用。使用LinkedHashMap實現
ScheduledCache:增加任務調度功能,超過時間,則自動清除
SerializedCache:增加序列化功能
SoftCache:增加基於軟引用實現的緩存管理策略
SynchronizedCache:增加同步功能
TransactionalCache:增加事務功能
WeakCache:增加弱引用實現的緩存管理策略
PerpetualCache:真正的緩存類,即被裝飾類

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