本文将通过阅读mybatis源码的方式详细分析mybatis查询的执行流程。
系列文档:
还是使用之前的示例代码。
public void testSelectBlogByBlogSearchParameter() throws ParseException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
Blog blog = new Blog();
blog.setContent("mybatis源码分析");
blog.setTitle("mybatis");
BlogSearchParameter parameter = new BlogSearchParameter();
parameter.setId(1);
parameter.setIds(ids);
parameter.setCreateTime(format.parse("2020-01-01 00:00:00"));
parameter.setBlog(blog);
List<Blog> list = session.selectList(
"org.net5ijy.mybatis.test.BlogMapper.selectBlogByParameter", parameter);
for (Blog b : list) {
System.out.println(b);
}
}
从之前openSession方法的分析可以知道这里使用的是DefaultSqlSession类型。
如下是方法实现:
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 这里的statement是MappedStatement的包含namespace的id全名
// 实际上就是从id -> MappedStatement映射中获取
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(
ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("");
} finally {
ErrorContext.instance().reset();
}
}
wrapCollection方法就是把list和array类型的参数做了以下封装,这里的key名值的注意:
public static Object wrapToMapIfCollection(Object object, String actualParamName) {
if (object instanceof Collection) {
ParamMap<Object> map = new ParamMap<>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
return map;
} else if (object != null && object.getClass().isArray()) {
ParamMap<Object> map = new ParamMap<>();
map.put("array", object);
Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
return map;
}
return object;
}
这个方法有两个实现,一个在BaseExecutor中,一个在CachingExecutor中,在之前创建Executor的时候,由于cacheEnabled默认是true,所以创建的是CachingExecutor对象,但是cache不是本次源码分析的重点内容(留到深入分析中做),遇到cache时会略过不做展开分析:
public <E> List<E> query(
MappedStatement ms, Object parameterObject,
RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 获取BoundSql
BoundSql boundSql = ms.getBoundSql(parameterObject);
// 创建CacheKey
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
// 重载query
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
BoundSql boundSql = ms.getBoundSql(parameterObject);
实现代码:
public BoundSql getBoundSql(Object parameterObject) {
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql =
new BoundSql(configuration, boundSql.getSql(),
parameterMap.getParameterMappings(), parameterObject);
}
// 这里有一个嵌套ResultMap的检查
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
public <E> List<E> query(
MappedStatement ms, Object parameterObject,
RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
// cache是null
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate
.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 所以直接执行到这里了
// 这里就是执行的BaseExecutor的query方法
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
// BaseExecutor的query方法
// 内部不重要的代码就删除掉了,不再记录
public <E> List<E> query(
MappedStatement ms, Object parameter,
RowBounds rowBounds, ResultHandler resultHandler,
CacheKey key, BoundSql boundSql) throws SQLException {
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
// 防止嵌套查询重复处理缓存
// 可以看出非线程安全
queryStack++;
// 获取一级缓存
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 真正的查询流程
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
queryStack、deferredLoads这些内容与嵌套查询、延迟加载、缓存等特性有关,暂时省略,不做展开分析,留到深入分析中做。
private <E> List<E> queryFromDatabase(
MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// 查询数据
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
// SimpleExecutor.doQuery
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
// 创建的是RoutingStatementHandler对象
// 而RoutingStatementHandler内部又根据ms.getStatementType()的值创建了不同类型的StatementHandler
// 在示例代码中,ms.getStatementType()的值是PREPARED,所以实际上创建的是PreparedStatementHandler对象
StatementHandler handler =
configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 创建JDBC的Statement
stmt = prepareStatement(handler, ms.getStatementLog());
// 查询数据
return handler.query(stmt, resultHandler);
} finally {
// 关闭Statement
closeStatement(stmt);
}
}
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;
}
stmt = prepareStatement(handler, ms.getStatementLog());
prepareStatement方法:
private Statement prepareStatement(
StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获取JDBC连接
Connection connection = getConnection(statementLog);
// 获取Statement
stmt = handler.prepare(connection, transaction.getTimeout());
// 给Statement设置参数
handler.parameterize(stmt);
return stmt;
}
protected Connection getConnection(Log statementLog) throws SQLException {
// 从JdbcTransaction获取JDBC连接
// 实际上就是从DataSource获取连接
// 从之前的数据源配置源码分析可以得知,这里使用的是PooledDataSource的实例
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
handler.prepare(connection, transaction.getTimeout())方法,实际上实现代码在BaseStatementHandler中:
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
Statement statement = null;
try {
// 这行代码比较重要,在PreparedStatementHandler类中
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);
}
}
// PreparedStatementHandler.instantiateStatement
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() == ResultSetType.DEFAULT) {
// 执行的是这个分支
// 就是JDBC的代码
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(
sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
给Statement设置参数,handler.parameterize(stmt)方法,这里比较重要:
// PreparedStatementHandler.parameterize
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
DefaultParameterHandler.setParameters方法:
public void setParameters(PreparedStatement ps) {
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
// 遍历parameterMapping
// 和SQL中的?是一一对应的关系
// 遍历结束之后,SQL中的每个参数都会被赋值
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)) {
// additionalParameter此处不展开,在深入分析中补充
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 typeHandler = parameterMapping.getTypeHandler();
// Jdbc类型
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 给Statement设置参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("...");
}
}
}
}
}
typeHandler.setParameter方法的示例:
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("");
}
try {
// 给Statement设置null值
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("...");
}
} else {
try {
// 设置非null值
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
throw new TypeException("...");
}
}
}
// 以IntegerTypeHandler为例
public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
throws SQLException {
ps.setInt(i, parameter);
}
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
// 执行JDBC查询
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
// 处理查询结果
return resultSetHandler.handleResultSets(ps);
}
resultSetHandler.handleResultSets方法,这个方法有很多用于处理多结果集和关联查询的内容,平时没有使用过,对其中的原理不是很了解,所以此处的分析仅限于单结果集,高级的内容留到后续的深入分析中去做:
public List<Object> handleResultSets(Statement stmt) throws SQLException {
// 封装查询结果
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 获取并封装JDBC查询的ResultSet
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 通常仅有一个ResultMap元素
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
// 值为1
int resultMapCount = resultMaps.size();
// 结果集和resultMapCount的合法性验证
validateResultMapsCount(rsw, resultMapCount);
// 在现阶段的分析中,此循环仅执行一次
while (rsw != null && resultMapCount > resultSetCount) {
// 获取ResultMap
ResultMap resultMap = resultMaps.get(resultSetCount);
// 此处是核心的结果集处理逻辑
handleResultSet(rsw, resultMap, multipleResults, null);
// 获取下一个结果集
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
// 下面的内容暂时不做分析,在深入分析中补充
String[] resultSets = mappedStatement.getResultSets();
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);
}
private void handleResultSet(
ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
// 执行这个分支
if (resultHandler == null) {
// 执行这个分支
DefaultResultHandler defaultResultHandler =
new DefaultResultHandler(objectFactory);
// 处理结果集
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 把结果放入集合
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
closeResultSet(rsw.getResultSet());
}
}
public void handleRowValues(
ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 嵌套查询留到后续的深入分析去做,这里只分析else分支
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(
rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
handleRowValuesForSimpleResultMap(
rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
private void handleRowValuesForSimpleResultMap(
ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
// 这里获取到JDBC的ResultSet对象
ResultSet resultSet = rsw.getResultSet();
// 一个跳行处理
skipRows(resultSet, rowBounds);
// resultSet.next()获取下一行结果,这是JDBC的代码
while (shouldProcessMoreRows(resultContext, rowBounds) &&
!resultSet.isClosed() &&
resultSet.next()) {
ResultMap discriminatedResultMap =
resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 封装一行结果
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// resultHandler是DefaultResultHandler的实例
// 这行代码的作用就是从resultContext中获取到结果然后保存到resultHandler中
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
private Object getRowValue(
ResultSetWrapper rsw, ResultMap resultMap,
String columnPrefix) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建一个行数据对象,内部有一些嵌套查询和懒加载的代码,不做展开分析
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 获取行数据类型的元信息,包括对象本身、数据类型、
// setter、getter、默认构造方法等
final MetaObject metaObject = configuration.newMetaObject(rowValue);
// 值为false
boolean foundValues = this.useConstructorMappings;
// 对于resultMap中没有做映射的列做自动化映射处理
// 代码比较多,但是思路与普通映射一样,不展开分析了
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) ||
foundValues;
}
// 使用JDBC行结果为行数据对象填充属性值
foundValues = applyPropertyMappings(
rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ?
rowValue : null;
}
return rowValue;
}
private boolean applyPropertyMappings(
ResultSetWrapper rsw, ResultMap resultMap,
MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
// 被映射列
final List<String> mappedColumnNames =
rsw.getMappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
// 遍历结束之后,一行数据对象就封装完成了
for (ResultMapping propertyMapping : propertyMappings) {
// 列名
String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
if (propertyMapping.getNestedResultMapId() != null) {
// the user added a column attribute to a nested result map, ignore it
column = null;
}
if (propertyMapping.isCompositeResult()
|| (column != null
&& mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
|| propertyMapping.getResultSet() != null) {
// 获取查询到的值
Object value = getPropertyMappingValue(
rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
// 获取属性名
final String property = propertyMapping.getProperty();
if (property == null) {
continue;
} else if (value == DEFERRED) {
foundValues = true;
continue;
}
if (value != null) {
foundValues = true;
}
if (value != null
|| (configuration.isCallSettersOnNulls()
&& !metaObject.getSetterType(property).isPrimitive())) {
// 为对象的指定属性赋值
metaObject.setValue(property, value);
}
}
}
return foundValues;
}
return collapseSingleResultList(multipleResults);
collapseSingleResultList方法:
private List<Object> collapseSingleResultList(List<Object> multipleResults) {
return multipleResults.size() == 1 ?
(List<Object>) multipleResults.get(0) : multipleResults;
}