Mybatis 執(zhí)行流程深入淺出
本文繼上篇mybatis
初始化流程后丧蘸,剖析其執(zhí)行流程
還是這幾個靈魂問題:
- Mybatis解決了什么問題? 無非是簡化數(shù)據(jù)庫操作怜珍、實現(xiàn)封裝恼策、讓程序員更關注SQL本身码倦、維護便利
- 它是如何解決這些問題的企孩?
- Mybatis是運行在什么樣的環(huán)境下的?
- 它如何讀取解析用戶定義的配置信息袁稽?即如何初始化的
- 它的環(huán)境結(jié)構(gòu)是什么樣的勿璃?
- 在這一環(huán)境下如何 實現(xiàn)做增刪查改
- 如何執(zhí)行SQL
- 如何執(zhí)行動態(tài)SQL
- 如何拼接查詢參數(shù)等等
上篇文章解答了 2問的 1、2推汽、3小問补疑,這篇文章就來說說剩下的幾個問題
也是大家使用得最多、最關心的問題
正經(jīng)的分割線
先給出一張圖歹撒,幫助大家能快速了解流程
同樣莲组,這里搬出我們上篇文章的TestCase
注意 閱讀
序號 (1)、(2)暖夭、(3)锹杈、(4)、(5)迈着、(6)...
Test.java
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(“xxx/mybatis.xml”);
// 使用一個SqlSession作為此次連接竭望, 主要講這兒,初始化流程
SqlSession sqlSession = sqlSessionFactory.openSession();
(1)動態(tài)代理獲取代理的mapper對象
CustomMapper mapper = sqlSession.getMapper(DemoMapper.class);
Map<String,Object> map = new HashMap<>();
map.put("id","1");
(4) 執(zhí)行代理對象的方法
System.out.println(mapper.select(map));
sqlSession.close();
獲取動態(tài)代理的mapper
DefaultSqlSession
(2)通過默認的sqlsession獲取到上篇文章講到的configuration(存儲著mappers)
@Override
public <T> T getMapper(Class<T> type) {
// 從
return configuration.getMapper(type, this);
}
MapperRegistry
(2)從knownMappers中拿到 代理工廠裕菠,使用工廠生成代理對象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
這里貼上關鍵點:本質(zhì)是通過Proxy.newProxyInstance 來生成的代理對象
MapperRegistry
(3)本質(zhì)是通過MapperProxyFactory
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
// 這里的 MapperProxy<T> implements InvocationHandler 借助了InvocationHandler咬清,實現(xiàn)invoke 方法,進而實現(xiàn)代理對象調(diào)用邏輯控制
具體調(diào)用請回到上面TestCase中的 (4)
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
執(zhí)行代理對象的方法
MapperProxy
(5)執(zhí)行具體方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
//如果是object類的默認方法奴潘,比如equals旧烧,hashcode什么的
return method.invoke(this, args);
} else if (method.isDefault()) {
//如果是default方法,java8画髓,9處理不同掘剪。但都是把方法綁定到代理對象再調(diào)用
if (privateLookupInMethod == null) {
return invokeDefaultMethodJava8(proxy, method, args);
} else {
return invokeDefaultMethodJava9(proxy, method, args);
}
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
// 重點來了
(6)獲取mapper執(zhí)行的方法
final MapperMethod mapperMethod = cachedMapperMethod(method);
(8)真正執(zhí)行傳進來的mapper操作
return mapperMethod.execute(sqlSession, args);
}
(7)看是否有緩存,如果沒有就創(chuàng)建新的 mapper的執(zhí)行方法
private MapperMethod cachedMapperMethod(Method method) {
return methodCache.computeIfAbsent(method,
k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
MapperMethod
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
// SQL的信息奈虾,select|insert|xxx杖小,初始化的MappedStatement等信息
this.command = new SqlCommand(config, mapperInterface, method);
// 當前執(zhí)行方法簽名肆汹,包含返回類型、resultHanlder予权、行范圍、查詢參數(shù)映射解析等信息
this.method = new MethodSignature(config, mapperInterface, method);
}
(8)執(zhí)行sql
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
// 如果是CUD操作浪册,將傳入的參數(shù)扫腺,映射到具體某個位置的SQL參數(shù)上
// CUD操作其實都是調(diào)用的 update方法, 詳見(9)
// 下面先講這個流程村象,select在之后講
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
······
}
增刪改 的流程
DefaultSqlSession
······
@Override
public int update(String statement, Object parameter) {
try {
(9)獲取MappedStatement笆环,通過執(zhí)行器執(zhí)行
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
······
SimpleExecutor
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 創(chuàng)建一個statement的處理器
(10)
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
(11)
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
(11)這里就是jdbc熟悉的,獲取連接厚者,準備Statement躁劣,設置參數(shù)到Statement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
// parameterHandler設置參數(shù)
handler.parameterize(stmt);
return stmt;
}
Configuration
(10)
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加入調(diào)用鏈里,返回代理的statementHandler库菲, 供插件用账忘, 分頁插件可通過這兒來攔截執(zhí)行
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
DefaultParameterHandler
public class DefaultParameterHandler implements ParameterHandler {
private final TypeHandlerRegistry typeHandlerRegistry;
private final MappedStatement mappedStatement;
private final Object parameterObject;
private final BoundSql boundSql;
private final 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;
}
(12)設置PreparedStatement 參數(shù)的邏輯
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
// 獲取到xml中配置的 參數(shù)
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();
// 首先看是否給參數(shù)設置了“額外”的名稱,如果是直接賦值
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
// 使用mybatis內(nèi)置的java常用類型的type映射
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
// 否則嘗試從元數(shù)據(jù)中嘗試獲取 值
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
// 都為空則各拷,通過null獲取type
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 設置對應參數(shù) -- 底層PreparedStatement.setxxx(i + 1, value)
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
}
PreparedStatementHandler
(13)給statement設置好參數(shù)后岖免,到通過PreparedStatementHandler真正執(zhí)行update的時候了
@Override
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
// 獲取affectRows數(shù)量
int rows = ps.getUpdateCount();
Object parameterObject = boundSql.getParameterObject();
// 主鍵返回后的執(zhí)行策略台腥,比如處理數(shù)據(jù)庫自增主鍵
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
到此增刪改操作流程全部結(jié)束
下面開始講Select執(zhí)行流程
和上述相同部分會一筆帶過,主要差異在結(jié)果集的映射上
這里 閱讀
序號重排 從mapper.select(map) 上的(4)開始蒋荚,(5)、(6)...
MapperMethod
(5)接著從MapperMethod開始
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
// 如果無返回值馆蠕,有結(jié)果集處理器
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
// 如果返回list
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
// 如果返回map
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
// 查詢下標
result = executeForCursor(sqlSession, args);
} else {
// 如果單個結(jié)果
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
(6)如果是多個則轉(zhuǎn)換成參數(shù)為map映射期升,單個則直接是當前參數(shù),沒有則為null
Object param = method.convertArgsToSqlCommandParam(args);
// 默認分頁互躬,rowBounds 基于內(nèi)存實現(xiàn)分頁播赁,不建議使用
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.selectList(command.getName(), param, rowBounds);
} else {
// 執(zhí)行查詢 詳見(9)
result = sqlSession.selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}
(7)通過解析器解析參數(shù),構(gòu)造參數(shù)映射
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);
}
ParamNameResolver
(8)解析names映射的地方吨铸,在mapper方法上添加了 @Param 注解行拢,會解析到names里
public ParamNameResolver(Configuration config, Method method) {
final Class<?>[] paramTypes = method.getParameterTypes();
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<>();
int paramCount = paramAnnotations.length;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
// skip special parameters
continue;
}
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// @Param was not specified.
//Spring MVC 底層調(diào)用的不是JDK的API Spring MVC底層是去解析字節(jié)碼
//在jdk8以前 調(diào)用這個getName 會有問題 arg0
//jdk8
if (config.isUseActualParamName()) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// use the parameter index as the name ("0", "1", ...)
// gcode issue #71
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
final Map<String, Object> param = new ParamMap<>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
//names : arg0,arg1
param.put(entry.getValue(), args[entry.getKey()]);
// add generic param names (param1, param2, ...)
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// ensure not to overwrite parameter named with @Param
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
DefaultSqlSession
(9)
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
// 通過執(zhí)行器執(zhí)行查詢
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();
}
}
BaseExecutor
(10)
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
(11)獲取緩存的key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
(12)
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
CacheKey cacheKey = new CacheKey();
// 根據(jù)SQL的id(com.DemoMapper.select),開啟分頁的查詢范圍(起始位置诞吱,查詢條數(shù))舟奠,SQL語句,從方法上傳過來的參數(shù)房维,返回的結(jié)果value值
// 五個條件來判斷沼瘫,是否是相同的查詢,做緩存key
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());
// 獲取到xml中配置的 參數(shù)
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
// mimic DefaultParameterHandler logic
// 這里與上面做CUD操作時的 (12)DefaultParameterHandler設置PreparedStatement參數(shù)的邏輯 相同咙俩,不再贅述
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
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);
}
// 通過獲取到的value更新 緩存key
cacheKey.update(value);
}
}
if (configuration.getEnvironment() != null) {
// issue #176
cacheKey.update(configuration.getEnvironment().getId());
}
return cacheKey;
}
// CacheKey類 中代碼計算hashcode
public void update(Object object) {
// 如果為空則為1耿戚,不為空判斷是否是數(shù)組湿故,不是直接返回對象hashcode,是則判斷具體是哪一種類型數(shù)組膜蛔,進行hash運算
int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);
//每update一次累加一次
count++;
checksum += baseHashCode;
baseHashCode *= count;
hashcode = multiplier * hashcode + baseHashCode;
updateList.add(object);
}
(12)執(zhí)行查詢
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 如果當前沒有經(jīng)歷過查詢坛猪,并且需要更新緩存
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
//對于數(shù)據(jù)庫的存儲過程進行輸出資源處理
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
(13)查詢
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;
}
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 {
(13)
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
(13)和上面CUD 相同的邏輯
@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());
(14)
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
PreparedStatementHandler
(14)
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
(15)處理結(jié)果集
return resultSetHandler.handleResultSets(ps);
}
DefaultResultSetHandler
(15)
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 有多個結(jié)果集取第一個,將ps取得的結(jié)果集 - ResultSet 包裝在 wrapper中皂股,其中還包含configuration信息
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
// 遍歷所有結(jié)果集
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
(16)處理單個結(jié)果集
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);
}
(16)
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 {
(17)處理具體一行的結(jié)果值
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
closeResultSet(rsw.getResultSet());
}
}
(17)
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) {
// 沒有分頁
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
(18)
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
ResultSet resultSet = rsw.getResultSet();
// 跳過分頁行
skipRows(resultSet, rowBounds);
// 遍歷resultSet
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
// 解析鑒別器墅茉,<discriminator>標簽 - 用于 當某個字段滿足一定條件時,使用指定的resultMap呜呐。比如
// <discriminator column="enabled" javaType="int">
// <case value="1" resultMap="testMap1"/>
// <case value="0" resultMap="testMap2"/>
// </discriminator>
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
(19)取值
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// 將取出來的值就斤,放入context中,再將context的值存入resultHandler
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
(19)
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
// 當需要進行循環(huán)結(jié)果集映射時蘑辑,使用到的懶加載 LoadPair
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 創(chuàng)建空map存儲值
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
// 有結(jié)果集的處理器
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 借助于初始化生成MetaObject信息 利用反射信息洋机,操作返回值
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
// 是否自動映射 通過resultMap 的 automapping屬性設置, 默認啟用
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// 自定義的映射 比如 通過resultMap 的 子標簽<id>洋魂、<result>設置
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
// 到這里查詢就結(jié)束了绷旗,后面就是上面的流程,關閉ps等資源忧设,然后將結(jié)果放入緩存等刁标。