Mybatis3.3.x技术内幕(五):Executor之doFlushStatements()

我们两清 提交于 2019-11-26 20:35:08

这天气,热的我满头大蒜。

在上一篇博文《五鼠闹东京之执行器Executor设计原本》中,已经对Executor做了比较详细的分析,但是,测试妹纸阅读完后,表示某些地方看不懂,毫不客气的给我提出了两点修改意见。

一、看完你的Statement和PrepareStatement批处理原理图,依然不明白为何一个编译Sql 3次,而另外一个编译Sql 1次。

二、对关闭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次。因为其中第1、2条Sql是完全相同的,只会编译1次。

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

对于PrepareStatement,支持问号“?”占位符,向数据库中插入id=[1,2,3]三条记录,对Sql只编译1次,由于减少了编译次数,大幅提高了效率。

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次,效率较低。

以上讨论,是在批处理情况下,二者的编译Sql表现。



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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!