这里,从头梳理Mybatis一次数据库查询过程,首先通过SqlSession
打开会话,使用会话获取到Mapper接口的代理对象,借助代理对象执行查询操作最终回到SqlSession
的selectList
方法,通过执行器Executor
发起一次查询操作
public class DefaultSqlSession implements SqlSession {
private final Executor executor;
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
// 通过executor发起一次查询操作
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();
}
}
}
Executor
通过StatementHandler
做进一步的操作
public class SimpleExecutor extends BaseExecutor {
@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());
// 通过StatementHandler进行进一步的操作
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
}
StatementHandler
中组装了ParameterHandler
、ResultSetHandler
,前者用来填充PreparedStatement
SQL语句中的?占位符,后者则用来处理查询数据库返回的ResultSet
结果集
public abstract class BaseStatementHandler implements StatementHandler {
protected final ResultSetHandler resultSetHandler;
protected final ParameterHandler parameterHandler;
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement,
Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler,
BoundSql boundSql) {
// ...
// 创建ParameterHandler
this.parameterHandler = configuration
.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 创建ResultSetHandler
this.resultSetHandler = configuration.newResultSetHandler(executor,
mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
如果当前使用PreparedStatement
进行数据库查询,则会使用PreparedStatementHandler
,它通过ParameterHandler
接口的实现类DefaultParameterHandler
为SQL语句填充占位符值
public class PreparedStatementHandler extends BaseStatementHandler {
protected final ParameterHandler parameterHandler;
public void parameterize(Statement statement) throws SQLException {
// 通过ParameterHandler发起设置占位符值操作
parameterHandler.setParameters((PreparedStatement) statement);
}
}
DefaultParameterHandler
通过TypeHandler
为SQL占位符填充属性值
public class DefaultParameterHandler implements ParameterHandler {
private final BoundSql boundSql;
public void setParameters(PreparedStatement ps) {
// ...
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
ParameterMapping parameterMapping = parameterMappings.get(i);
TypeHandler typeHandler = parameterMapping.getTypeHandler();
try {
// 通过TypeHandler设置占位符
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
}
}
}
最后使用ResultSetHandler
处理返回结果集合,封装成需要的对象返回
public class SimpleStatementHandler extends BaseStatementHandler {
protected final ResultSetHandler resultSetHandler;
/**
* 无论是查询一条记录或者多条记录,Mybatis统一使用查询多条记录的逻辑
* 如果是多条记录会在SqlSession中获取集合第一个元素返回
*/
public <E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
// 通过ResultSetHandler处理结果集
return resultSetHandler.handleResultSets(statement);
}
}
综上所述,以下为Mybatis的简要架构图
Mybatis架构