详述mybatis执行流程

系列

  • MyBatis拦截器原理介绍
  • Mybatis拦截器改写请求参数和结果
  • Mybatis 插件兼容动态SQL
  • mybatis 参数解析流程附相关案例
  • 详述mybatis执行流程

开篇

  • 写这篇文章纯粹是为了更好的理顺 mybatis 的执行流程。
  • mybatis 的执行流程具体可参考下面的流程图,基于 mybatis 3.4.6版本进行的分析。
mybatis执行流程
  • 核心流程一是指mapperMethod的执行流程,这个过程主要是指请求参数的解析。
  • 核心流程二是指executor的执行流程,这个过程主要是指StatementHandler的创建,包含 BoundSql 的创建、parameterHandler和 ResultSetHandler 的创建。
  • StatementHandler 执行流程,这部分主要执行 SQL 并对结果集进行处理。
  • 核心点:参数的组装在 exector 之前前,同样在所有的拦截器执行前,BoundSql的时机在于 statementHandler 的创建,早于parameterHandler和 ResultSetHandler 的时机。

MapperMethod

MapperMethod对象创建

public class MapperProxy 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);

    // 执行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的核心在于创建MapperMethod对象。
  • MapperMethod的对象的创建过程中涉及mybatis内部请求参数的封装。
  • 通过执行mapperMethod的execute方法继续执行

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);
    // 创建MethodSignature对象
    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);
      // 创建ParamNameResolver参数解析对象
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }

    public Object convertArgsToSqlCommandParam(Object[] args) {
      return paramNameResolver.getNamedParams(args);
    }
}
  • MapperMethod的创建核心在于构建方法签名参数MethodSignature。
  • MethodSignature的convertArgsToSqlCommandParam完成mybatis请求参数的封装。

MapperMethod执行流程

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: {
        // 调用MethodSignature的convertArgsToSqlCommandParam参数转换方法
        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通过MapperMethod#convertArgsToSqlCommandParam完成参数请求参数的解析。
  • 执行DefaultSqlSession的update/insert/select/delete等操作。
  • 参数的解析convertArgsToSqlCommandParam在真正执行 Executor 方法之前
public class ParamNameResolver {

  private static final String GENERIC_NAME_PREFIX = "param";
  private final SortedMap 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 param = new ParamMap();
      int i = 0;
      for (Map.Entry 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负责完成mybatis请求参数的组装。


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);
      // 执行的是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执行的过渡。
  • 参数的组装在执行 executor 之前,核心结论就是参数的解析组装在 executor 执行前


Executor

Executor的执行流程

public class CachingExecutor implements Executor {

  private final Executor delegate;
  private final TransactionalCacheManager tcm = new TransactionalCacheManager();

  public CachingExecutor(Executor delegate) {
    // delegate是SimpleExecutor对象
    this.delegate = delegate;
    delegate.setExecutorWrapper(this);
  }

  @Override
  public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms);
    // 执行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、创建StatementHandler对象
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      // 2、初始化请求参数
      stmt = prepareStatement(handler, ms.getStatementLog());
      // 3、执行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());
    // 初始化参数信息
    handler.parameterize(stmt);
    return stmt;
  }
}
  • Executor从CachingExecutor到SimpleExecutor的顺序进行执行,核心在SimpleExecutor当中。
  • SimpleExecutor#doUpdate的核心流程包括:1、创建StatementHandler对象;2、参数初始化prepareStatement;3、执行StatementHandler的 update 操作。
  • 创建StatementHandler的过程中完成了 BoundSql 的执行、parameterHandler和 ResultSetHandler 的创建
  • prepareStatement内部会执行parameterHandler的方法。
  • BoundSql的生成早于prepareStatement方法的执行,因此mybatis 原有的顺序必然导致parameterHandler的执行结果无法影响 BoundSql 的执行。


StatementHandler流程执行

public class Configuration {

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // 创建 StatementHandler 
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    // 针对 StatementHandler 进行拦截
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);

    return statementHandler;
  }
}


public class RoutingStatementHandler implements StatementHandler {
  // delegate 是PreparedStatementHandler对象
  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 对象
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;
    // 2、创建parameterHandler对象
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);

    // 3、创建resultSetHandler对象
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }
}
  • RoutingStatementHandler内部创建的是PreparedStatementHandler。
  • PreparedStatementHandler的创建中包含:boundSql的生成、parameterHandler和resultSetHandler的创建
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();

    // 对插入和更新操作处理自增 id 的操作
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
  }

  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();

    // 对结果进行处理
    return resultSetHandler. handleResultSets(ps);
  }

  @Override
  public  Cursor queryCursor(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();

    // 对结果进行处理
    return resultSetHandler. handleCursorResultSets(ps);
  }
}
  • PreparedStatementHandler的执行后针对 update 操作后会进行主键的设置(通过KeyGenerator设置);针对 select 操作后执行resultSetHandler的执行动作。

你可能感兴趣的:(详述mybatis执行流程)