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)。(通过网络爬虫或转载的文章,常常丢失流程图、时序图,格式错乱等,仍是看原版的比较好)

相关文章
相关标签/搜索