Mybatis__doFlushStatements

本文探讨了Mybatis的Executor执行器及其子类中doFlushStatements方法的作用,该方法主要用于刷新Statement。在不同类型的Executor中,如BaseExecutor、SimpleExecutor、BatchExecutor和ReuseExecutor,doFlushStatements的实现有所不同。BaseExecutor在commit、rollback和close时都会调用该方法。SimpleExecutor不缓存Statement,因此实现为空;而BatchExecutor和ReuseExecutor由于缓存Statement,因此在doFlushStatements中执行特定操作。

相信看过Mybatis的执行器Executor以及5个子类源码的朋友应该对FlushStatements和doFlushSatements知道吧,这里我们说说它的作用,顾名思义的话了就是刷新Statement,我们知道在执行器就是执行Statement的,在进行提交,回滚等事务操作以及DML操作时,需要刷新Statement,在不同的Executor执行器中因为缓存执行器需要缓存,SimpleStatement执行完就关闭Statement,ReuseExecutor执行完不关闭而是返回Map集合中,等,所以在各执行器中的doFlushSatements也是不同的。

BaseExecutor
我们知道BaseExecutor是Executor顶层接口的子类,也是执行器类的基类,它基本实现了Update和quart还有commit,rollback等功能,还有定义了抽象方法doUpdate(),doQuery(), doFlushStatement()给其子类去实现符合各自的方法,它也简单的实现了flushStatement的功能,也定义了doFlushStatement抽象方法给子类去实现。

@Override
  public List<BatchResult> flushStatements() throws SQLException {
	
    return flushStatements(false);
  }

  public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException {
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    return doFlushStatements(isRollBack);
  }


/**
   * 事务提交
   */
  @Override
  public void commit(boolean required) throws SQLException {
    if (closed) {
      throw new ExecutorException("Cannot commit, transaction is already closed");
    }
    //清除缓存
    clearLocalCache();
    //flushStatements里,不传参数,默认是false,不进行事务回滚
    flushStatements();
    if (required) {
      //事务提交
      transaction.commit();
    }
  }
  /**
   * 事务回滚
   */
  @Override
  public void rollback(boolean required) throws SQLException {
    if (!closed) {
      try {
    	//清除缓存
        clearLocalCache();
        //刷新Statement,进行事务回滚
        flushStatements(true);
      } finally {
        if (required) {
          //事务回滚
          transaction.rollback();
        }
      }
    }
  }

// 定义的四个抽象方法,在相应方法中被调用,Update,FlushStatements,Query,QueryCursor
protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
      throws SQLException;

从源码可以看出,
每当调用commit、rollback、close方法时,都会先调用doFlushStatements(),然后再commit、rollback、close。同样适用于其他的Executor实现类。

SimpleExecutor

@Override
  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    return Collections.emptyList();
  }


@SuppressWarnings("unchecked")
    public static final <T> List<T> emptyList() {
        return (List<T>) EMPTY_LIST;
}

@SuppressWarnings("rawtypes")
    public static final List EMPTY_LIST = new EmptyList<>();

从源码可以看出:在SimpleExecutor中,实现了doFlushStatements,但是它返回的是一个空集合,SimpleExecutor是最简单的执行器,没有缓存Statement对象,每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。根据对应的sql直接执行即可,不会做一些额外的操作。

BatchExecutor

    所调用的flushStatements其实就是调用了doFlushStatements
  @Override
  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    try {
      List < BatchResult > results = new ArrayList < BatchResult >();
      //默认isRollback为false,如果true,进行了事务回滚返回空列表
      if (isRollback) {
        return Collections.emptyList();
      }
      for (int i = 0, n = statementList.size(); i < n; i++) {//遍历所有satement
        Statement stmt = statementList.get(i);
        applyTransactionTimeout(stmt);
        //获取对应的结果对象
        BatchResult batchResult = batchResultList.get(i);
        try {
        //stmt.executeBatch执行批处理,并将更新条数保存到执行结果中;
          batchResult.setUpdateCounts(stmt.executeBatch());
        //获取结果对应到mappedStatement
          MappedStatement ms = batchResult.getMappedStatement();
        //获取参数列表
          List<Object> parameterObjects = batchResult.getParameterObjects();
KeyGenerator keyGenerator = ms.getKeyGenerator();
          if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
            Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
            jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
          } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
            for (Object parameter : parameterObjects) {
              keyGenerator.processAfter(this, ms, stmt, parameter);
            }
          }
          // Close statement to close cursor #1109
          //关闭Staement
          closeStatement(stmt);
        } catch (BatchUpdateException e) {
          StringBuilder message = new StringBuilder();
          message.append(batchResult.getMappedStatement().getId())
              .append(" (batch index #")
              .append(i + 1)
              .append(")")
              .append(" failed.");
          if (i > 0) {
            message.append(" ")
                .append(i)
                .append(" prior sub executor(s) completed successfully, but will be rolled back.");
          }
          throw new BatchExecutorException(message.toString(), e, results, batchResult);
        }
        results.add(batchResult);
      }
      return results;
    } finally {
      for (Statement stmt : statementList) {//遍历一个个的关闭Statement
        closeStatement(stmt);
      }
      currentSql = null;
      statementList.clear();
      batchResultList.clear();
    }
  }

BatchExecutor内保存的Statement对象内,都是有等待执行的Sql批处理命令的,所以,先执行stmt.executeBatch(),保存执行结果,然后再close。

ReuseExecutor

@Override
  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    for (Statement stmt : statementMap.values()) {//遍历statementMap 关闭Statement
      closeStatement(stmt);
    }
    statementMap.clear();//清除statementMap
    //返回空列表
    return Collections.emptyList();
  }

在Executor的实现类中,只有ReuseExecutor和BatchExecutor缓存了Statement对象,所以,其他的Executor对doFlushStatements()进行了空实现。

flushStatements()调用时机
时序图:
在这里插入图片描述
每当调用commit、rollback、close方法时,都会先调用doFlushStatements(),然后再commit、rollback、close。
在Executor的实现类中,只有ReuseExecutor和BatchExecutor缓存了Statement对象,所以,其他的Executor对doFlushStatements()进行了空实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偷偷学习被我发现

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值