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.