Mybatis3.3.x技術內幕(五):Executor之doFlushStatements()

這天氣,熱的我滿頭大蒜。java

在上一篇博文《五鼠鬧東京之執行器Executor設計本來》中,已經對Executor作了比較詳細的分析,可是,測試妹紙閱讀完後,表示某些地方看不懂,絕不客氣的給我提出了兩點修改意見。web

1、看完你的Statement和PrepareStatement批處理原理圖,依然不明白爲什麼一個編譯Sql 3次,而另一個編譯Sql 1次。sql

2、對關閉Statement對象一筆帶過,不夠清晰。數據庫

我準備亡羊補牢,針對上面的兩個問題進行補充完善。
緩存



1.Statement和PrepareStatement在批處理時對Sql的編譯策略

insert into students(id) values(1);
insert into students(id) values(1);
insert into students(id) values(2);
insert into students(id) values(3);

上面的4個Sql,不管是Statement,仍是PrepareStatement,對Sql都編譯3次。由於其中第一、2條Sql是徹底相同的,只會編譯1次。
網絡

insert into students(id) values(?); // id=[1,2,3]

對於PrepareStatement,支持問號「?」佔位符,向數據庫中插入id=[1,2,3]三條記錄,對Sql只編譯1次,因爲減小了編譯次數,大幅提升了效率。
ide

Statement不支持問號「?」佔位符,向數據庫中插入id=[1,2,3]三條記錄,只能寫成下面這樣。
測試

insert into students(id) values(1);
insert into students(id) values(2);
insert into students(id) values(3);

因爲Sql不一樣,因此編譯3次,效率較低。spa

以上討論,是在批處理狀況下,兩者的編譯Sql表現。.net



2.doFlushStatements()

ReuseExecutor.doFlushStatements()。

  @Override
  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    for (Statement stmt : statementMap.values()) {
      closeStatement(stmt);
    }
    statementMap.clear();
    return Collections.emptyList();
  }

Reuse的Statement內,並無未執行的Sql命令,因此直接close便可。



BatchExecutor.doFlushStatements()。

@Override
  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    try {
      List<BatchResult> results = new ArrayList<BatchResult>();
      if (isRollback) {
        return Collections.emptyList();
      }
      for (int i = 0, n = statementList.size(); i < n; i++) {
        Statement stmt = statementList.get(i);
        BatchResult batchResult = batchResultList.get(i);
        try {
          // executeBatch()
          batchResult.setUpdateCounts(stmt.executeBatch());
          //...
        results.add(batchResult);
      }
      return results;
    } finally {
      for (Statement stmt : statementList) {
        closeStatement(stmt);
      }
      currentSql = null;
      statementList.clear();
      batchResultList.clear();
    }
  }

BatchExecutor內保存的Statement對象內,都是有等待執行的Sql批處理命令的,因此,先執行stmt.executeBatch(),保存執行結果,而後再close。


Executor的實現類中,只有ReuseExecutor和BatchExecutor緩存了Statement對象,因此,其餘的Executor對doFlushStatements()進行了空實現。


3.flushStatements()調用時機時序圖

(Made In Visual Paradigm)

即,每當調用commit、rollback、close方法時,都會先調用doFlushStatements(),而後再commit、rollback、close。

上圖一樣適用於其餘的Executor實現類。


結語:設計原則中,有一條是「單一職責」原則,受其啓發,博文也採起「單一職責」原則,一篇博文儘可能分析一類知識點,避免跳躍性暈眩。

另外,大牛黃勇先生,搞了一個smartweb項目,大牛紅薯先生,搞了一個J2Cache項目,大牛羅果先生,更是搞了一個高大上的Tiny項目……,羨慕崇拜之餘,仍是靜下心來,夯實基礎,但願之後咱也能體驗下大牛的無敵最寂寞。


版權提示:文章出自開源中國社區,若對文章感興趣,可關注個人開源中國社區博客(http://my.oschina.net/zudajun)。(通過網絡爬蟲或轉載的文章,常常丟失流程圖、時序圖,格式錯亂等,仍是看原版的比較好)

相關文章
相關標籤/搜索