In-depth analysis of the running process of mybatis (3)

We know that: through XMLConfigBuild, we obtain the configuration object that parses the xml configuration file, and then we use it to create the SQLSessionFactory, which is encapsulated into a SQLSessionFactoryBuild class; with the SQLSessionFactory, we can directly obtain the SQLSession object; then We also analyzed the running process of SQLSession, which is a Mapper object generated by the dynamic proxy of the mapper's registrar, and then looked at the process of his dynamic proxy generation, and came here:

  private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) {
    Map<K, V> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey(), rowBounds);
    } else {
      result = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey());
    }
    return result;
  }

Now let's continue to see how SQLSession executes sql statements for us:

It calls the Map<K, V> selectMap method of sqlSession. Let's look at its implementation. Its implementation is in the DefaultSqlSession class.

@Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
    return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
    final List<? extends V> list = selectList(statement, parameter, rowBounds);
    final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<K, V>(mapKey,
        configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
    final DefaultResultContext<V> context = new DefaultResultContext<V>();
    for (V o : list) {
      context.nextResultObject(o);
      mapResultHandler.handleResult(context);
    }
    return mapResultHandler.getMappedResults();
  }

Keep reading:

final List<? extends V> list = selectList(statement, parameter, rowBounds);
Through this method, we found the executor, the source code is as follows:
  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

what is executor? It is an executor and one of the four major objects under SQLSession; it schedules the other three objects, statementHandler, ParameterHandler, ResultSetHandler, etc., to execute sql.

Then we continue to talk about the role of the other three objects:

1) statementHandler: Make the statement of the database perform operations, it is the core and plays a role in linking the previous and the next;

2) ParameterHandler: used to process sql parameters;

3) ResultSetHandler: It executes data return processing;

Then we continue to see how it is scheduled:

return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

We entered layer by layer and finally found the doQuery method under org.apache.ibatis.executor.SimpleExecutor and the prepareStatement method to be called under it:

@Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } 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;
  }

Obviously, we can see the StatementHandler constructed by mybatis according to the configuration, and then call the prepareStatement method to compile the sql and initialize the parameters; its process is:

1) First, the prepare method of StatementHandler is called to perform pre-compilation and basic settings:

stmt = handler.prepare(connection, transaction.getTimeout());

2) Then set the parameters through the parameterize method of StatementHandler

handler.parameterize(stmt);

after entering

  @Override
  public void parameterize(Statement statement) throws SQLException {
    parameterHandler.setParameters((PreparedStatement) statement);
  }
We saw the processing by parameterHandler;

Then hand over the processed object to the <E> query method of StatementHandler for execution:

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    statement.execute(sql);
    return resultSetHandler.<E>handleResultSets(statement);
  }

We continue to follow up:

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    return delegate.<E>query(statement, resultHandler);
  }
Here we enter RoutingStatementHandler, which implements the StatementHandler interface,

public class RoutingStatementHandler implements StatementHandler {

  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:
        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());
    }

We can see that it creates the StatementHandler object and then we find the resultSetHandler

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.<E> handleResultSets(ps);
  }
Here, the process of how the entire SQLSession handles and executes sql will be understood;

Briefly describe the process, as shown above.



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325592214&siteId=291194637