A text to let you know Mybatis seconds operating principle of SqlSession

Foreword

SqlSession is one of the most important building Mybatis, you can simply think Mybatis purpose is to generate a series of configuration similar to JDBC Connection object generated SqlSession objects, so as to open "communication" with the database, CRUD can be achieved by SqlSession (of course, now more is recommended to use Interface Mapper form), then it is how to implement to achieve, and this is what this blog introduced, which will involve a simple explanation of the source.

SqlSession understand the principle of operation is the only way to learn Mybatis plug-in, plug-ins because Mybatis will "insert" in the course of operation SqlSession run, if not well understood, then, Mybatis plug-in might override the corresponding source code cause serious problems. In view of this, this blog as much as possible detailed principle of operation SqlSession!

1, SqlSession brief

(1) SqlSession simple principle introduction

SqlSession provide select / insert / update / delete methods that SqlSession interfaces that use the old version, but the new version will Mybatis recommended method Mapper interface.

Mapper is actually a dynamic proxy object, go to MapperMethod execute method can simply delete the SqlSession find, update, query, selection methods, from the bottom to achieve it: Through dynamic agent technology, so that the interface up and running, after using the command mode , finally adopted SqlSession interface methods (getMapper () method until Mapper) to perform SQL queries (that is the underlying implementation Mapper interface methods or the use of SqlSession interface method implementation).

  Note: Although only a simple description, but in fact the source code is relatively complex, the source below with a brief introduction!

(2) SqlSession important four objects

 1) Execute: scheduling execution StatementHandler, ParmmeterHandler, ResultHandler performed corresponding SQL statement;

2) StatementHandler: Use Statement (PrepareStatement) perform database operations, i.e., the bottom is a good package of the prepareStatement;

3) ParammeterHandler: SQL processing parameters;

4) ResultHandler: ResultSet encapsulation process returns the result set.

2, SqlSession four objects

(1) Execute actuator:

  Actuators play a crucial role, which is what the real implementation of Java interacts with the database, query execution process involved the entire SQL.

1) There are three main actuator: the SIMPLE simple actuator (the actuator is not arranged is the default), the REUSE a reuse prepared statements, BATCH batch updates, special purpose processors batch

package org.apache.ibatis.session;

/**

* @author Clinton Begin

*/

public enum ExecutorType {

SIMPLE, REUSE, BATCH

}

2) actuator acts: Executor will first call StatementHandler the prepare () method for precompiled SQL statement, and set some basic operating parameters, and then call StatementHandler of parameterize () method (actually ParameterHandler setting parameters) to enable the setting parameters, resultHandler reassembled query results returned to the caller to complete a pre-compiled query is completed, that is simply summed up the first pre-compiled SQL statement, after setting parameters (with prepareStatement process similar to JDBC) Finally, if there is a query result will return to the assembly.

First, SimpleExecutor for example, view the source code we get a few important points are as follows:

First: Executor select the appropriate method of the actuator generated by the Configuration object newExecutor ()

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {

executorType = executorType == null ? defaultExecutorType : executorType;

executorType = executorType == null ? ExecutorType.SIMPLE : executorType;

Executor executor;

if (ExecutorType.BATCH == executorType) {

executor = new BatchExecutor(this, transaction);

} else if (ExecutorType.REUSE == executorType) {

executor = new ReuseExecutor(this, transaction);

} else {

executor = new SimpleExecutor(this, transaction);

}

if (cacheEnabled) {

executor = new CachingExecutor(executor);

}

executor = (Executor) interceptorChain.pluginAll(executor);

return executor;

}

Note: The last interceptorChain.pluginAll execute () in layers of dynamic proxies, can be modified in the last plug-in code before calling the real Executor, which is why learn Mybatis plug-ins need to know to run the process SqlSession)

Second: the actuator StatementHandler constructed according to Configuration

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

StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);

stmt = prepareStatement(handler, ms.getStatementLog());

return handler.update(stmt);

} finally {

closeStatement(stmt);

}

}

Third: Executor executes prepare StatementHandler's () method is precompiled ----> Fill connection object and other parameters ----> then call parameterize () method to set the parameters ----> complete precompiled

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;

}

Summing up the above drawing simple thinking is as follows:

SqlSession operating principle of Mybatis


(2) StatementHanlder database session is

 1)作用:简单来说就是专门处理数据库会话。详细来说就是进行预编译并且调用ParameterHandler的setParameters()方法设置参数。

2)数据库会话器主要有三种:SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler,分别对应Executor的三种执行器(SIMPLE、REUSE、BATCH)

我们从上述Executor的prepareStatement()方法中调用了StatementHandler的parameterize()开始一步步地查看源码,如下得到几点重要的知识点:小编整理了一套java架构资料和BAT面试题,加659270626领取,限前20名,先到先得。

第一:StatementHandler的生成是由Configuration方法中newStatementHandler()方法生成的,但是正在创建的是实现了StatementHandler接口的RoutingStatementHandler对象

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject,

                               RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);

statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);

return statementHandler;

}

第二:RoutingStatementHandler的通过适配器模式找到对应(根据上下文)的StatementHandler执行的,并且有SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler,分别对应Executor的三种执行器(SIMPLE、REUSE、BATCH)

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

}

之后主要以PrepareStatementHandler为例,我们观察到:它是实现BaseStatementHandler接口的,最后BaseStatementHandler又是实现StatementHandler接口的

public class PreparedStatementHandler extends BaseStatementHandler

......

public abstract class BaseStatementHandler implements StatementHandler

它主要有三种方法:prepare、parameterize和query,我们查看源码:

第三:在BaseStatementHandler中重写prepare()方法,instantiateStatement()方法完成预编译,之后设置一些基础配置(获取最大行数,超时)

@Override

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {

ErrorContext.instance().sql(boundSql.getSql());

Statement statement = null;

try {

statement = instantiateStatement(connection);

setStatementTimeout(statement, transactionTimeout);

setFetchSize(statement);

return statement;

} catch (SQLException e) {

closeStatement(statement);

throw e;

} catch (Exception e) {

closeStatement(statement);

throw new ExecutorException("Error preparing statement. Cause: " + e, e);

}

}

第四:instantiateStatement()预编译实际上也是使用了JDBC的prepareStatement()完成预编译

@Override

protected Statement instantiateStatement(Connection connection) throws SQLException {

String sql = boundSql.getSql();

if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {

String[] keyColumnNames = mappedStatement.getKeyColumns();

if (keyColumnNames == null) {

return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);

} else {

return connection.prepareStatement(sql, keyColumnNames);

}

} else if (mappedStatement.getResultSetType() != null) {

return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);

} else {

return connection.prepareStatement(sql);

}

}

第五:在prepareStatement中重写parameterize()方法。prepare()预编译完成之后,Executor会调用parameterize()方法(在上面的Executor部分中已经做了介绍),实际上是调用ParameterHandler的setParameters()方法

@Override

public void parameterize(Statement statement) throws SQLException {

parameterHandler.setParameters((PreparedStatement) statement);

}

(3)ParameterHandler参数处理器

作用:对预编译中参数进行设置,如果有配置typeHandler,自然会对注册的typeHandler对参数进行处理

查看并学习源码,得到以下几点重要知识点:

第一:Mybatis提供了ParamterHandler的默认实现类DefalutParameterHandler

SqlSession operating principle of Mybatis


public interface ParameterHandler {

Object getParameterObject();

void setParameters(PreparedStatement ps)

throws SQLException;

}

其中:getParameterObject是返回参数对象,setParameters()是设置预编译参数)

 第二:从parameterObject中取到参数,然后使用typeHandler(注册在Configuration中)进行参数处理:

@Override

public void setParameters(PreparedStatement ps) {

ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());

List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

if (parameterMappings != null) {

for (int i = 0; i < parameterMappings.size(); i++) {

ParameterMapping parameterMapping = parameterMappings.get(i);

if (parameterMapping.getMode() != ParameterMode.OUT) {

Object value;

String propertyName = parameterMapping.getProperty();

if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params

value = boundSql.getAdditionalParameter(propertyName);

} else if (parameterObject == null) {

value = null;

} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {

value = parameterObject;

} else {

MetaObject metaObject = configuration.newMetaObject(parameterObject);

value = metaObject.getValue(propertyName);

}

TypeHandler typeHandler = parameterMapping.getTypeHandler();

JdbcType jdbcType = parameterMapping.getJdbcType();

if (value == null && jdbcType == null) {

jdbcType = configuration.getJdbcTypeForNull();

}

try {

typeHandler.setParameter(ps, i + 1, value, jdbcType);

} catch (TypeException e) {

throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);

} catch (SQLException e) {

throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);

}

}

}

}

}

(4)ResultSetHandler结果集处理器

作用:很简单,就是组装结果返回结果集

第一:ResultSetHandler接口,handlerResultSets()是包装并返回结果集的,handleOutputParameters()是处理存储过程输出参数的

public interface ResultSetHandler {

<E> List<E> handleResultSets(Statement stmt) throws SQLException;

<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;

void handleOutputParameters(CallableStatement cs) throws SQLException;

 第二:Mybatis提供了默认的ResultSetHandler实现类DefaultResultSetHandler,其中重点是handlerResultSets()的实现,但是其实现过程比较复杂,这里不过多介绍(emmmmm....个人目前能力还达理解,仍需努力)

SqlSession operating principle of Mybatis


第三:在Executor中doQuery()方法返回了封装的结果集

@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);

}

}

第四:实际上是返回结果是调用了resultSetHandler的handleResultSets()方法

@Override

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {

PreparedStatement ps = (PreparedStatement) statement;

ps.execute();

return resultSetHandler.<E> handleResultSets(ps);

}

3、SqlSession运行总结

(1)文字总结

 SqlSession的运行主要是依靠Executor执行器调用(调度)StatementHandler、parameterHanlder、ResultSetHandler,Executor首先通过创建StamentHandler执行预编译并设置参数运行,而整个过程需要如下几步才能完成:

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;

}

1)prepare预编译SQL

由适配模式生成的RoutingStatementHandler根据上下文选择生成三种相应的XXXStatementHandler;

在生成的XXXStatementHandler内部instantiateStatement()方法执行底层JDBC的prepareStatement()方法完成预编译

2) parameterize setting parameters

The default is DefaultParameterHandler (parameterHandler implements the interface) in the setParameter () method of configuring the parameters, wherein the parameter is removed from ParameterObject, the processing to typeHandler

3) doUpdate / doQuery execute SQL

Results returned by the default DefaultResultSetHandler (ResultSetHandler implements interface) Package

(2) summary diagram

1) SqlSession FIG running total internal

SqlSession operating principle of Mybatis


2) prepare () method of operating FIG: 3) parameterize () method of the diagram

SqlSession operating principle of Mybatis


SqlSession operating principle of Mybatis


Guess you like

Origin blog.51cto.com/14028890/2421539