StatementHandler是连接Mybatis和JDBC之间的桥梁
。
在执行SQL之前,StatementHandler
需要创建合适的 Statement 对象,然后通过ParameterHandler
将参数值填充到 Statement 对象中,最后通过 Statement.execute()
执行 SQL。SQL 执行完后,通过ResultSetHandler
处理结果。
//-☆☆- SimpleExecutor
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();
//NOTE☆: 创建StatementHandler(创建时会加载配置的拦截器Interceptor)
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//NOTE☆: 创建Statement(和JDBC开始关联)
stmt = prepareStatement(handler, ms.getStatementLog());
//NOTE☆: 调用StatementHandler来真正地执行SQL命令
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
调用configuration.newStatementHandler
创建StatementHandler,实际创建的是RoutingStatementHandler对象,其作用是根据不同的StatementType来进行路由并创建不同的StatementHandler。(相当于一个装饰器模式或者策略模式),Configuration在创建StatementHandler时直接创建RoutingStatementHandler,在其内部用StatementHandler delegate;
来记录正在的StatementHandler。后续所有关于StatementHandler的操作都会经过RoutingStatementHandler的相应方法来执行。
加入拦截器Interceptor
,会为真正的StatementHandler进行封装,最后返回的是一个代理类(通过工具Plugin.wrap)
见插件Interceptor篇
该方法的作用是绑定执行时所需要的实参,即把运行时参数设置到SQL中。
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//NOTE: 获取数据库连接
Connection connection = getConnection(statementLog);
//NOTE: 创建Statement
stmt = handler.prepare(connection, transaction.getTimeout());
//NOTE: 参数设置
handler.parameterize(stmt);
return stmt;
}
Mybatis自身提供了PooledDataSource 和 UnpooledDataSource两种数据源,会在JdbcTransaction中通过openConnection()方法去获取Connection。(当在实际应用中会用其他的数据源来代替,就看怎么给Mybatis进行配置了)
PreparedStatementHandler
内部依赖于java.sql.PreparedStatement对象来完成数据库的相关操作。
实现StatementHandler接口的抽象类,提供了一些参数绑定的公用方法、构建ParameterHandler和ResultSetHandler
、以及针对插入更新删除操作会先生成自增主键。而具体的数据库操作还是在对应的StatementHandler中实现。
protected final Configuration configuration;
protected final ObjectFactory objectFactory;
protected final TypeHandlerRegistry typeHandlerRegistry;
//NOTE: 将结果集映射成结果对象
protected final ResultSetHandler resultSetHandler;
//NOTE:为SQL语句绑定实参,也就是使用传入的实参替换SQL语句中的"?"占位符
protected final ParameterHandler parameterHandler;
//NOTE: 记录执行SQL的Executor对象
protected final Executor executor;
//NOTE: 记录SQL语句对应的MappedStatement和BoundSql
protected final MappedStatement mappedStatement;
protected BoundSql boundSql;
protected final RowBounds rowBounds;
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();
//NOTE: <1> 如果 boundSql 为空,一般是写类操作,例如:insert、update、delete ,则先获得自增主键,然后再创建 BoundSql 对象
if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
//创建ParameterHandler和ResultSetHandler
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
//PreparedStatementHandler
return connection.prepareStatement(....)
handler.parameterize(stmt)
,参数设置会使用在BaseStatementHandler中创建的ParameterHandler。
DefaultParameterHandler
public void setParameters(PreparedStatement ps) {
//NOTE: 获取SQL片段对应的ParameterMapping(与每个#{xxx}占位符都会生成一个ParameterMapping对象)
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) {
//NOTE: 参数值
Object value;
//NOTE: 参数名称
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)){
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
//NOTE: 若有对应JavaType的TypeHandler,则直接返回parameterObject,因为可以直接通过TypeHandler转化为对应的jdbcType
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
//NOTE: 可能会是对象,然后找对应属性的值,或者是一个Map则找对应key的value
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
//NOTE: 根据不同的typeHandler来设置参数值
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
//NOTE: 使用typeHandler 设置对应 #{} 位置的具体参数值
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
.....
}
}
}
}
}
上述已创建Statement并对于其进行实参绑定,接下来开始正在的sql执行。(以创建PreparedStatement
和PreparedStatementHandler
为例)
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
//NOTE: PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
//NOTE: 执行SQL
ps.execute();
//NOTE: 用ResultSetHandler处理执行结果
return resultSetHandler.handleResultSets(ps);
}