天天看點

聊聊Mybatis的Executor之模闆方法模式

聊聊Mybatis的Executor之模闆方法模式

模闆方法模式通過模闆方法來指定流程,具體的子類來實作具體的邏輯。

我們看一下Executor接口,它的實作類有BaseExecutor抽象類和CachingExecutor類

BaseExecutor

BaseExecutor抽象類作為模闆方法的抽象模闆類,它把緩存和事務進行實作,具體變化的對資料庫操作的部分由子類去實作

送出事務方法

我們先說說事務管理的commit()方法的實作:

@Override
  public void commit(boolean required) throws SQLException {
    if (closed) {
      throw new ExecutorException("Cannot commit, transaction is already closed");
    }
    clearLocalCache();
    flushStatements();
    if (required) {
      transaction.commit();
    }
  }
  
           
  1. 清除一級緩存
  2. 調用flushStatements()方法,這個方法中調用doFlushStatements抽象方法,具體操作由子類來實作,主要功能就是清除Statement對象
  3. 最後送出事務

復原事務的邏輯和這個送出邏輯基本一緻,就不再分析了

Mybatis預設開啟一級緩存,是SqlSession級别的,即通過SqlSession建立會話,如果在這個會話中執行相同的sql,第一次執行的結果會進行緩存,再往後從緩存中查找

緩存資料

我們從它的query()方法來進行分析:

@Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  }
           
  1. 先通過createCacheKey()來建立CacheKey對象
  2. 根據select标簽的 flushCache配置,決定在查詢前是否清空緩存,将其設定為 true 後,隻要語句被調用,都會導緻本地緩存和二級緩存被清空,預設值是false。
  3. 通過

    list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;

    這段代碼可以看出先通過CacheKey對象來擷取緩存,如果緩存為空的話再調用queryFromDatabase()方法從資料庫中查詢資料,再放入緩存中,下次使用的時候就能從緩存中取
  4. 最後周遊DeferredLoad對象集合處理嵌套查詢,具體的調用

    deferredLoad.load();

    方法
  5. 根據setting标簽的localCacheScope配置,決定緩存範圍,預設值為 SESSION,會緩存一個會話中執行的所有查詢。 若設定值為 STATEMENT,本地緩存将僅用于執行語句,對相同 SqlSession 的不同查詢将不會進行緩存。
cacheKey.update(ms.getId());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());
           

總結