实际上SqlSession的执行过程就是通过Executor、StatementHandler、ParameterHandler、ResultSetHandler这四个对象来完成对数据库的操作和返回结果的。
一、Executor(接口)
它是一个执行器,真正进行java与数据库交互的对象,实际干活的,而SqlSession就是个门面。
/**
* 执行器
*
*/
public interface Executor {
//不需要ResultHandler
ResultHandler NO_RESULT_HANDLER = null;
//更新
int update(MappedStatement ms, Object parameter) throws SQLException;
//查询,带分页,带缓存,BoundSql
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
//查询,带分页
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
//刷新批处理语句
List<BatchResult> flushStatements() throws SQLException;
//提交和回滚,参数是否要强制
void commit(boolean required) throws SQLException;
void rollback(boolean required) throws SQLException;
//创建CacheKey
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
//判断是否缓存了
boolean isCached(MappedStatement ms, CacheKey key);
//清理Session缓存
void clearLocalCache();
//延迟加载
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
Transaction getTransaction();
void close(boolean forceRollback);
boolean isClosed();
void setExecutorWrapper(Executor executor);
}
它有一个实现的抽象类BaseExecutor(执行器基类)和类CachingExecutor(二级缓存执行器)。我们主要看BaseExcutor, 它有三个重要的子类:SimpleExecutor(简单执行器)、ReuseExecutor(可重用的执行器)、BatchExecutor(批量专用执行器)。
再来查看Configuration创建Executor:
//默认为简单执行器
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;//枚举类,下面提供源码
public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType);
}
//产生执行器
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
//这句再做一下保护,防止粗心大意的人将defaultExecutorType设成null?
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
//然后就是简单的3个分支,产生3种执行器BatchExecutor/ReuseExecutor/SimpleExecutor
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);
}
//如果要求缓存,生成另一种CachingExecutor(默认就是有缓存),装饰者模式,所以默认都是返回CachingExecutor
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
//此处调用插件,通过插件可以改变Executor行为
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
/**
* 执行器的类型
*
*/
public enum ExecutorType {
//ExecutorType.SIMPLE
//这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。
//ExecutorType.REUSE
//这个执行器类型会复用预处理语句。
//ExecutorType.BATCH
//这个执行器会批量执行所有更新语句,如果SELECT在它们中间执行还会标定它们是必须的,来保证一个简单并易于理解的行为。
SIMPLE, REUSE, BATCH
}
如代码注释所说,拦截Executor。构建一层层动态代理对象,我们可以修改在执行真正的Executor方法之前来配置插件的代码,这就是插件的原理。再看看执行Executor的方法,其中有多个类,我们了解一下简单执行器SimpleExecutor的方法:
public class SimpleExecutor extends BaseExecutor {
public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
//update
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
//新建一个StatementHandler
//这里看到ResultHandler传入的是null
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//准备语句
stmt = prepareStatement(handler, ms.getStatementLog());
//StatementHandler.update
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
//select
@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
//这里看到ResultHandler传入了
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//准备语句
stmt = prepareStatement(handler, ms.getStatementLog());
//StatementHandler.query
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
//doFlushStatements只是给batch用的,所以这里返回空
return Collections.emptyList();
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
//调用StatementHandler.prepare
stmt = handler.prepare(connection);
//调用StatementHandler.parameterize
handler.parameterize(stmt);
return stmt;
}
}
不管是doUpdate方法还是doQuery方法,到后面都是去执行StatementHandler的prepare进行预编译及相关设置,其中StatementHandler构建也是通过Configuration的:
//创建语句处理器
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;
}
其他的执行器与简单执行器的走法基本差不多,不多赘述,提供相关源码参考(可跳过下面源码部分了解下一个内容StatementHandler):
public class ReuseExecutor extends BaseExecutor {
//可重用的执行器内部用了一个map,用来缓存SQL语句对应的Statement
private final Map<String, Statement> statementMap = new HashMap<String, Statement>();
public ReuseExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Configuration configuration = ms.getConfiguration();
//和SimpleExecutor一样,新建一个StatementHandler
//这里看到ResultHandler传入的是null
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//准备语句
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
}
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
}
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
for (Statement stmt : statementMap.values()) {
closeStatement(stmt);
}
statementMap.clear();
return Collections.emptyList();
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//得到绑定的SQL语句
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
//如果缓存中已经有了,直接得到Statement
if (hasStatementFor(sql)) {
stmt = getStatement(sql);
} else {
//如果缓存没有找到,则和SimpleExecutor处理完全一样,然后加入缓存
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection);
putStatement(sql, stmt);
}
handler.parameterize(stmt);
return stmt;
}
private boolean hasStatementFor(String sql) {
try {
return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed();
} catch (SQLException e) {
return false;
}
}
private Statement getStatement(String s) {
return statementMap.get(s);
}
private void putStatement(String sql, Statement stmt) {
statementMap.put(sql, stmt);
}
}
二、StatementHandler(接口)
它是语句处理器,处理数据库会话的。上面提供了关于Configuration生成StatementHandler代码,现在先看StatementHandler源码( 注意:新的Jar包中prepare中新增一个参数Integer):
public interface StatementHandler {
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;//新的jar包中新增了一个参数
//准备语句
//Statement prepare(Connection connection)
// throws SQLException;
//参数化
void parameterize(Statement statement)
throws SQLException;
//批处理
void batch(Statement statement)
throws SQLException;
//update
int update(Statement statement)
throws SQLException;
//select-->结果给ResultHandler
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
//得到绑定sql
BoundSql getBoundSql();
//得到参数处理器
ParameterHandler getParameterHandler();
}
StatementHandler有一个抽象实现类BaseStatementHandler和一个实现类RoutingStatementHandler,BaseStatementHandler有三个子类:
PreparedStatementHandler
CallableStatementHandler
SimpleStatementHandler
在Configuration中生成StatementHandler就三句代码,创建的实际对象为RoutingStatementHandler对象,它也是与Executor一样的,都是用代理对象来封装的。
观察RoutingStatementHandler就会发现其中的巧妙之处:
/**
* 路由选择语句处理器,有点像代理模式
*
*/
public class RoutingStatementHandler implements StatementHandler {
//定义一个对象适配器
private final StatementHandler delegate;//这个对象很重要!!!例如分页插件就会用到此变量
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据语句类型,委派到不同的语句处理器(STATEMENT|PREPARED|CALLABLE)
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());
}
}
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
return delegate.prepare(connection, transactionTimeout);
}
@Override
public void parameterize(Statement statement) throws SQLException {
delegate.parameterize(statement);
}
@Override
public void batch(Statement statement) throws SQLException {
delegate.batch(statement);
}
@Override
public int update(Statement statement) throws SQLException {
return delegate.update(statement);
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
return delegate.<E>query(statement, resultHandler);
}
@Override
public BoundSql getBoundSql() {
return delegate.getBoundSql();
}
@Override
public ParameterHandler getParameterHandler() {
return delegate.getParameterHandler();
}
}
通过配置来选择具体的StatementHandler对象,我们来查看常用的PreparedStatementHandler(预处理语句处理器),由于其父类已经将prepare方法实现了:
父类BaseStatementHandler
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//实例化Statement
statement = instantiateStatement(connection);//对SQL进行预编译等操作
//设置超时
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);
}
}
//如何实例化Statement,交给子类做
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
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.execute和PreparedStatement.getUpdateCount
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
int rows = ps.getUpdateCount();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
@Override
public void batch(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.addBatch();
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
//调用Connection.prepareStatement
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);
}
}
//设置参数
@Override
public void parameterize(Statement statement) throws SQLException {
//调用ParameterHandler.setParameters
parameterHandler.setParameters((PreparedStatement) statement);
}
}
设置参数是通过ParameterHandler处理的。接下来开始看下一个对象----ParameterHandler。
三、ParameterHandler:
它是对预编译语句进行参数的设置,完成对预编译参数的设置。
/**
* 参数处理器
*
*/
public interface ParameterHandler {
//得到参数
Object getParameterObject();
//设置参数
void setParameters(PreparedStatement ps)
throws SQLException;
}
它仅有一个默认的实现类:DefaultParameterHandler
**
* 默认参数处理器
*
*/
public class DefaultParameterHandler implements ParameterHandler {
private final TypeHandlerRegistry typeHandlerRegistry;
private final MappedStatement mappedStatement;
private final Object parameterObject;
private BoundSql boundSql;
private Configuration configuration;
public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
this.mappedStatement = mappedStatement;
this.configuration = mappedStatement.getConfiguration();
this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
this.parameterObject = parameterObject;
this.boundSql = boundSql;
}
@Override
public Object getParameterObject() {
return parameterObject;
}
//设置参数
@Override
public void setParameters(PreparedStatement ps) throws SQLException {
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) {
//如果不是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) {
//若参数为null,直接设null
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
//若参数有相应的TypeHandler,直接设object
value = parameterObject;
} else {
//除此以外,MetaObject.getValue反射取得值设进去
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
//不同类型的set方法不同,所以委派给子类的setParameter方法
jdbcType = configuration.getJdbcTypeForNull();
}
typeHandler.setParameter(ps, i + 1, value, jdbcType);
}
}
}
}
}
把取到的参数(parameterObject)转换后(typeHandler),注册到Configuration中(typeHandler也是在其中配置好的)。
四、ResultSetHandler
/**
* 结果集处理器
*
*/
public interface ResultSetHandler {
//处理结果集
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
//处理OUT参数
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
mybatis已经为我们提供了一个默认实现类:DefaultResultSetHandler
由于其源码内容较多,节选部分参考:
@Override
public void handleOutputParameters(CallableStatement cs) throws SQLException {
final Object parameterObject = parameterHandler.getParameterObject();
final MetaObject metaParam = configuration.newMetaObject(parameterObject);
final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
//循环处理每个参数
for (int i = 0; i < parameterMappings.size(); i++) {
final ParameterMapping parameterMapping = parameterMappings.get(i);
//只处理OUT|INOUT
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
if (ResultSet.class.equals(parameterMapping.getJavaType())) {
//如果是ResultSet型(游标)
//#{result, jdbcType=CURSOR, mode=OUT, javaType=ResultSet, resultMap=userResultMap}
//先用CallableStatement.getObject取得这个游标,作为参数传进去
handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
} else {
//否则是普通型,核心就是CallableStatement.getXXX取得值
final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
}
}
}
}
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<Object>();
int resultSetCount = 0;
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
//一般resultMaps里只有一个元素
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResulSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
由于实际操作中对它的改变几率低,不再讨论。
总结
通过上面的解析,我们了解了Mybatis执行SQL的流程:Executor先调用StatementHandler里prepa方法预编译SQL语句,并设置参数,然后再用parameterize方法来使用ParameterHandler设置参数,完成预编译,执行查询的话,使用ResultHandler将结果返回给调用者,其他操作也类似。