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

被折叠的 条评论
为什么被折叠?



