系列
- MyBatis攔截器原理介紹
- Mybatis攔截器改寫(xiě)請(qǐng)求參數(shù)和結(jié)果
- Mybatis 插件兼容動(dòng)態(tài)SQL
- mybatis 參數(shù)解析流程附相關(guān)案例
- 詳述mybatis執(zhí)行流程
開(kāi)篇
- 寫(xiě)這篇文章純粹是為了更好的理順 mybatis 的執(zhí)行流程。
- mybatis 的執(zhí)行流程具體可參考下面的流程圖,基于 mybatis 3.4.6版本進(jìn)行的分析。

mybatis執(zhí)行流程
- 核心流程一是指mapperMethod的執(zhí)行流程,這個(gè)過(guò)程主要是指請(qǐng)求參數(shù)的解析。
- 核心流程二是指executor的執(zhí)行流程,這個(gè)過(guò)程主要是指StatementHandler的創(chuàng)建,包含 BoundSql 的創(chuàng)建、parameterHandler和 ResultSetHandler 的創(chuàng)建。
- StatementHandler 執(zhí)行流程,這部分主要執(zhí)行 SQL 并對(duì)結(jié)果集進(jìn)行處理。
- 核心點(diǎn):參數(shù)的組裝在 exector 之前前,同樣在所有的攔截器執(zhí)行前,BoundSql的時(shí)機(jī)在于 statementHandler 的創(chuàng)建,早于parameterHandler和 ResultSetHandler 的時(shí)機(jī)。
MapperMethod
MapperMethod對(duì)象創(chuàng)建
public class MapperProxy<T> implements InvocationHandler, Serializable {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
// 執(zhí)行MapperMethod的 execute 方法
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}
- MapperProxy的核心在于創(chuàng)建MapperMethod對(duì)象。
- MapperMethod的對(duì)象的創(chuàng)建過(guò)程中涉及mybatis內(nèi)部請(qǐng)求參數(shù)的封裝。
-
通過(guò)執(zhí)行mapperMethod的execute方法繼續(xù)執(zhí)行。
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
// 創(chuàng)建MethodSignature對(duì)象
this.method = new MethodSignature(config, mapperInterface, method);
}
public static class MethodSignature {
private final boolean returnsMany;
private final boolean returnsMap;
private final boolean returnsVoid;
private final boolean returnsCursor;
private final Class<?> returnType;
private final String mapKey;
private final Integer resultHandlerIndex;
private final Integer rowBoundsIndex;
private final ParamNameResolver paramNameResolver;
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
this.returnsVoid = void.class.equals(this.returnType);
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
this.returnsCursor = Cursor.class.equals(this.returnType);
this.mapKey = getMapKey(method);
this.returnsMap = this.mapKey != null;
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
// 創(chuàng)建ParamNameResolver參數(shù)解析對(duì)象
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);
}
}
- MapperMethod的創(chuàng)建核心在于構(gòu)建方法簽名參數(shù)MethodSignature。
- MethodSignature的convertArgsToSqlCommandParam完成mybatis請(qǐng)求參數(shù)的封裝。
MapperMethod執(zhí)行流程
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
// 調(diào)用MethodSignature的convertArgsToSqlCommandParam參數(shù)轉(zhuǎn)換方法
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
return result;
}
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);
}
}
- MapperMethod#execute通過(guò)MapperMethod#convertArgsToSqlCommandParam完成參數(shù)請(qǐng)求參數(shù)的解析。
- 執(zhí)行DefaultSqlSession的update/insert/select/delete等操作。
- 參數(shù)的解析convertArgsToSqlCommandParam在真正執(zhí)行 Executor 方法之前
public class ParamNameResolver {
private static final String GENERIC_NAME_PREFIX = "param";
private final SortedMap<Integer, String> names;
private boolean hasParamAnnotation;
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
final Map<String, Object> param = new ParamMap<Object>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
param.put(entry.getValue(), args[entry.getKey()]);
// add generic param names (param1, param2, ...)
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// ensure not to overwrite parameter named with @Param
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
}
- ParamNameResolver負(fù)責(zé)完成mybatis請(qǐng)求參數(shù)的組裝。
DefaultSqlSession
public class DefaultSqlSession implements SqlSession {
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
// 執(zhí)行的是CachingExecutor的 update 方法
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
}
- DefaultSqlSession起到連接executor執(zhí)行的過(guò)渡。
- 參數(shù)的組裝在執(zhí)行 executor 之前,核心結(jié)論就是參數(shù)的解析組裝在 executor 執(zhí)行前
Executor
Executor的執(zhí)行流程
public class CachingExecutor implements Executor {
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
public CachingExecutor(Executor delegate) {
// delegate是SimpleExecutor對(duì)象
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms);
// 執(zhí)行SimpleExecutor的update方法
return delegate.update(ms, parameterObject);
}
}
public class SimpleExecutor extends BaseExecutor {
public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 1、創(chuàng)建StatementHandler對(duì)象
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 2、初始化請(qǐng)求參數(shù)
stmt = prepareStatement(handler, ms.getStatementLog());
// 3、執(zhí)行StatementHandler的 update 操作
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
// 初始化參數(shù)信息
handler.parameterize(stmt);
return stmt;
}
}
- Executor從CachingExecutor到SimpleExecutor的順序進(jìn)行執(zhí)行,核心在SimpleExecutor當(dāng)中。
- SimpleExecutor#doUpdate的核心流程包括:1、創(chuàng)建StatementHandler對(duì)象;2、參數(shù)初始化prepareStatement;3、執(zhí)行StatementHandler的 update 操作。
- 創(chuàng)建StatementHandler的過(guò)程中完成了 BoundSql 的執(zhí)行、parameterHandler和 ResultSetHandler 的創(chuàng)建。
- prepareStatement內(nèi)部會(huì)執(zhí)行parameterHandler的方法。
- BoundSql的生成早于prepareStatement方法的執(zhí)行,因此mybatis 原有的順序必然導(dǎo)致parameterHandler的執(zhí)行結(jié)果無(wú)法影響 BoundSql 的執(zhí)行。
StatementHandler流程執(zhí)行
public class Configuration {
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 創(chuàng)建 StatementHandler
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 針對(duì) StatementHandler 進(jìn)行攔截
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
}
public class RoutingStatementHandler implements StatementHandler {
// delegate 是PreparedStatementHandler對(duì)象
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED: // 使用的 SQL
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
@Override
public int update(Statement statement) throws SQLException {
return delegate.update(statement);
}
}
public class PreparedStatementHandler extends BaseStatementHandler {
protected final Configuration configuration;
protected final ObjectFactory objectFactory;
protected final TypeHandlerRegistry typeHandlerRegistry;
protected final ResultSetHandler resultSetHandler;
protected final ParameterHandler parameterHandler;
protected final Executor executor;
protected final MappedStatement mappedStatement;
protected final RowBounds rowBounds;
protected BoundSql boundSql;
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
public abstract class BaseStatementHandler implements StatementHandler {
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
// 1、獲取 boundSql 對(duì)象
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
// 2、創(chuàng)建parameterHandler對(duì)象
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 3、創(chuàng)建resultSetHandler對(duì)象
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
}
- RoutingStatementHandler內(nèi)部創(chuàng)建的是PreparedStatementHandler。
- PreparedStatementHandler的創(chuàng)建中包含:boundSql的生成、parameterHandler和resultSetHandler的創(chuàng)建。
public class PreparedStatementHandler extends BaseStatementHandler {
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
@Override
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
int rows = ps.getUpdateCount();
Object parameterObject = boundSql.getParameterObject();
// 對(duì)插入和更新操作處理自增 id 的操作
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
// 對(duì)結(jié)果進(jìn)行處理
return resultSetHandler.<E> handleResultSets(ps);
}
@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
// 對(duì)結(jié)果進(jìn)行處理
return resultSetHandler.<E> handleCursorResultSets(ps);
}
}
- PreparedStatementHandler的執(zhí)行后針對(duì) update 操作后會(huì)進(jìn)行主鍵的設(shè)置(通過(guò)KeyGenerator設(shè)置);針對(duì) select 操作后執(zhí)行resultSetHandler的執(zhí)行動(dòng)作。