1. 程式人生 > >Mybatis之是如何執行你的SQL的(SQL執行過程,引數解析過程,結果集封裝過程)

Mybatis之是如何執行你的SQL的(SQL執行過程,引數解析過程,結果集封裝過程)

Myabtis的SQL的執行是通過SqlSession。預設的實現類是DefalutSqlSession。通過原始碼可以發現,selectOne最終會呼叫selectList這個方法。

 1   @Override
 2   public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
 3     try {
     //獲取MappedStatement 通過id 到configuration裡面
4 MappedStatement ms = configuration.getMappedStatement(statement);
5 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); 6 } catch (Exception e) { 7 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); 8 } finally { 9 ErrorContext.instance().reset(); 10 } 11
}

通過上面可以發現是通過Executor去執行查詢。但是executor是個介面,是什麼時候指定的用什麼執行器呢。

因為SqlSession是通過SqlSessionFactory介面獲取的,實現類是DefaultSqlSessionFactory

 1   private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
 2     Transaction tx = null;
 3     try
{ 4 final Environment environment = configuration.getEnvironment(); 5 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); 6 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); 7 final Executor executor = configuration.newExecutor(tx, execType); 8 return new DefaultSqlSession(configuration, executor, autoCommit); 9 } catch (Exception e) { 10 closeTransaction(tx); // may have fetched a connection so lets call close() 11 throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); 12 } finally { 13 ErrorContext.instance().reset(); 14 } 15 }
 1 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
 2     executorType = executorType == null ? defaultExecutorType : executorType;
 3     executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
 4     Executor executor;
 5     if (ExecutorType.BATCH == executorType) {
 6       executor = new BatchExecutor(this, transaction);
 7     } else if (ExecutorType.REUSE == executorType) {
 8       executor = new ReuseExecutor(this, transaction);
 9     } else {
10       executor = new SimpleExecutor(this, transaction);
11     }
12     if (cacheEnabled) {
13       executor = new CachingExecutor(executor);
14     }
15     executor = (Executor) interceptorChain.pluginAll(executor);
16     return executor;
17   }

可以看到預設的是SimpleExecutor;然後預設的是開啟快取的,所以最終應該是一個CachingExecutor,但是CachingExecutor有一個構造器引數是前面的執行器。

這是一種典型的裝飾器設計模式

下面那行程式碼你現在只需要知道如果有Executor的攔截器,就會返回一個代理物件,在執行executor方法前,會執行攔截器。這是動態代理。

後面講Myabtis攔截器原理的時候會詳細介紹。

這下知道了是CachingExecotor,來看下CachingExecutor方法;

1  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
2     BoundSql boundSql = ms.getBoundSql(parameterObject);
3     CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
4     return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
5   }

① 先看是如何獲取BoundSql  這個物件,包含了sql,params等資訊。

 1   public BoundSql getBoundSql(Object parameterObject) {
 2     BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
 3     List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
 4     if (parameterMappings == null || parameterMappings.isEmpty()) {
 5       boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
 6     }
 7 
 8     // check for nested result maps in parameter mappings (issue #30)
 9     for (ParameterMapping pm : boundSql.getParameterMappings()) {
10       String rmId = pm.getResultMapId();
11       if (rmId != null) {
12         ResultMap rm = configuration.getResultMap(rmId);
13         if (rm != null) {
14           hasNestedResultMaps |= rm.hasNestedResultMaps();
15         }
16       }
17     }

可以發現從sqlSource中獲取BoundSql

一,DynamicSqlSourcre

 1 public class DynamicSqlSource implements SqlSource {
 2 
 3   private Configuration configuration;
 4   private SqlNode rootSqlNode;
 5 
 6   public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
 7     this.configuration = configuration;
 8     this.rootSqlNode = rootSqlNode;
 9   }
10 
11   @Override
12   public BoundSql getBoundSql(Object parameterObject) {
這一塊的操作就是替換sql裡面${}部分
13 DynamicContext context = new DynamicContext(configuration, parameterObject); 14 rootSqlNode.apply(context); 15 SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); 16 Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); 17 SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); 18 BoundSql boundSql = sqlSource.getBoundSql(parameterObject); 19 for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { 20 boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); 21 } 22 return boundSql; 23 } 24 25 }

來看下是如何替換sql的:

 1   public DynamicContext(Configuration configuration, Object parameterObject) {
 2     if (parameterObject != null && !(parameterObject instanceof Map)) {
//如果引數型別不是map則構造一個MetaObject; //todo 這一塊幹嘛的目前還不清楚,後面研究mybatis反射時候研究
//這個物件 儲存著Configuration的那個幾個factory 反射factory 駝峰Factory,建立物件factory
3 MetaObject metaObject = configuration.newMetaObject(parameterObject); 4 bindings = new ContextMap(metaObject); 5 } else { 6 bindings = new ContextMap(null); 7 } 8 bindings.put(PARAMETER_OBJECT_KEY, parameterObject);//_paramter 9 bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId()); 10 }

rootSqlNode.apply實際上介面的方法,這是根據節點的類別去執行,我們正常的MixedSqlNode實際上就是SqlNode陣列型別,

 

這裡只拿TextSqlNode做例子來看:

1   @Override
2   public boolean apply(DynamicContext context) {
3     GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
4     context.appendSql(parser.parse(text));
5     return true;
6   }

看過上一篇的應該對這段有了解, 就是用具體解析類來解析節點內容來,parser獲取${}中間變數的名字,然後BindingTokenParser去處理;

parser.parses就是把sql裡面每個${}替換成相應的值的作用

 1     public BindingTokenParser(DynamicContext context, Pattern injectionFilter) {
 2       this.context = context;
 3       this.injectionFilter = injectionFilter;
 4     }
 5 
 6     @Override
 7     public String handleToken(String content) {
//從引數物件裡面獲取值返回
8 Object parameter = context.getBindings().get("_parameter"); 9 if (parameter == null) { 10 context.getBindings().put("value", null);
//是不是基本型別
11 } else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) { 12 context.getBindings().put("value", parameter); 13 }
//獲取到對應值,這一塊很複雜,有時間在研究。
14 Object value = OgnlCache.getValue(content, context.getBindings()); 15 String srtValue = (value == null ? "" : String.valueOf(value)); // issue #274 return "" instead of "null" 16 checkInjection(srtValue); 17 return srtValue; 18 } 19 20 private void checkInjection(String value) { 21 if (injectionFilter != null && !injectionFilter.matcher(value).matches()) { 22 throw new ScriptingException("Invalid input. Please conform to regex" + injectionFilter.pattern()); 23 } 24 } 25 }

好了 到此為止 sql裡面${}都已經替換成該有的值了,根據變數名獲取Value這一塊下回研究下在另外寫篇文章。

然後看這段程式碼:

SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);

這一段也很重要 實際上是填充boundSql裡面parameterMapping的

來看SqlSourceBuilder

1   public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
2     ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
3     GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
4     String sql = parser.parse(originalSql);
5     return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
6   }

這一塊程式碼應該很熟悉了吧, 實際上就是把#{}替換成? 同時記錄下引數的型別等資訊,因為邏輯前面有介紹,直接看ParameterMappingTokenHandler的方法

 1     public String handleToken(String content) {
//記錄引數
2 parameterMappings.add(buildParameterMapping(content));
//替換成?
3 return "?"; 4 } 5 6 private ParameterMapping buildParameterMapping(String content) { 7 Map<String, String> propertiesMap = parseParameterMapping(content); 8 String property = propertiesMap.get("property"); 9 Class<?> propertyType; 10 if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params 11 propertyType = metaParameters.getGetterType(property); 12 } else if (typeHandlerRegistry.hasTypeHandler(parameterType)) { 13 propertyType = parameterType; 14 } else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) { 15 propertyType = java.sql.ResultSet.class; 16 } else if (property != null) { 17 MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory()); 18 if (metaClass.hasGetter(property)) { 19 propertyType = metaClass.getGetterType(property); 20 } else { 21 propertyType = Object.class; 22 } 23 } else { 24 propertyType = Object.class; 25 } 26 ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType); 27 Class<?> javaType = propertyType;
設定每個引數型別等。
28 String typeHandlerAlias = null; 29 for (Map.Entry<String, String> entry : propertiesMap.entrySet()) { 30 String name = entry.getKey(); 31 String value = entry.getValue(); 32 if ("javaType".equals(name)) { 33 javaType = resolveClass(value); 34 builder.javaType(javaType); 35 } else if ("jdbcType".equals(name)) { 36 builder.jdbcType(resolveJdbcType(value)); 37 } else if ("mode".equals(name)) { 38 builder.mode(resolveParameterMode(value)); 39 } else if ("numericScale".equals(name)) { 40 builder.numericScale(Integer.valueOf(value)); 41 } else if ("resultMap".equals(name)) { 42 builder.resultMapId(value); 43 } else if ("typeHandler".equals(name)) { 44 typeHandlerAlias = value; 45 } else if ("jdbcTypeName".equals(name)) { 46 builder.jdbcTypeName(value); 47 } else if ("property".equals(name)) { 48 // Do Nothing 49 } else if ("expression".equals(name)) { 50 throw new BuilderException("Expression based parameters are not supported yet"); 51 } else { 52 throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}. Valid properties are " + parameterProperties); 53 } 54 } 55 if (typeHandlerAlias != null) { 56 builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias)); 57 } 58 return builder.build(); 59 }

 

現在回過頭開始看CachingExecutor的query方法了

 1   public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
 2       throws SQLException {
//這塊就是mybatis的二級快取
3 Cache cache = ms.getCache(); 4 if (cache != null) { 5 flushCacheIfRequired(ms); 6 if (ms.isUseCache() && resultHandler == null) { 7 ensureNoOutParams(ms, parameterObject, boundSql); 8 @SuppressWarnings("unchecked") 9 List<E> list = (List<E>) tcm.getObject(cache, key); 10 if (list == null) { 11 list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 12 tcm.putObject(cache, key, list); // issue #578 and #116 13 } 14 return list; 15 } 16 }
//最終呼叫的還是CachingExecutor裡裝飾的那個執行器
17 return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 18 }

這個方法是所有執行器父類的BaseExecutor來實現的

 1   public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
 2     ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
 3     if (closed) {
 4       throw new ExecutorException("Executor was closed.");
 5     }
 6     if (queryStack == 0 && ms.isFlushCacheRequired()) {
 7       clearLocalCache();
 8     }
 9     List<E> list;
10     try {
11       queryStack++;
12       list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
13       if (list != null) {
14         handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
15       } else {
16         list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
17       }
18     } finally {
19       queryStack--;
20     }
21     if (queryStack == 0) {
22       for (DeferredLoad deferredLoad : deferredLoads) {
23         deferredLoad.load();
24       }
25       // issue #601
26       deferredLoads.clear();
27       if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
28         // issue #482
29         clearLocalCache();
30       }
31     }
32     return list;
33   }

//這裡應該就是mybatis的一級快取,直接看從資料庫查詢資料

 1   private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
 2     List<E> list;
 3     localCache.putObject(key, EXECUTION_PLACEHOLDER);
 4     try {
     //在子類中實現的 doQuery 查詢出來結果放入一級快取
5 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); 6 } finally { 7 localCache.removeObject(key); 8 } 9 localCache.putObject(key, list); 10 if (ms.getStatementType() == StatementType.CALLABLE) { 11 localOutputParameterCache.putObject(key, parameter); 12 } 13 return list; 14 }

看SimpleExecutor的doQuery的實現

 1   public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
 2     Statement stmt = null;
 3     try {
 4       Configuration configuration = ms.getConfiguration();
//建立StatementHandler的代理物件,有的話返回代理物件,沒有返回預設的RoutingStatmenthandler 典型的責任鏈模式
5 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); 6 stmt = prepareStatement(handler, ms.getStatementLog()); 7 return handler.<E>query(stmt, resultHandler); 8 } finally { 9 closeStatement(stmt); 10 } 11 }

接下來看下是怎麼建立合適的Statement物件的,

1   private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
2     Statement stmt;
3     Connection connection = getConnection(statementLog);
4     stmt = handler.prepare(connection);
5     handler.parameterize(stmt);//設定引數
6     return stmt;
7   }

RoutingStatmenthandler

1 @Override
2 public Statement prepare(Connection connection) throws SQLException {
3   return delegate.prepare(connection);
4 }
5 
6 @Override
7 public void parameterize(Statement statement) throws SQLException {
8   delegate.parameterize(statement);
9 }

呼叫的都是裝飾的statementHander ,delegate是在RoutingStatementHandler構造器初始化的;

 1  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
 2 
 3     switch (ms.getStatementType()) {
 4       case STATEMENT:
 5         delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
 6         break;
 7       case PREPARED:
 8         delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
 9         break;
10       case CALLABLE:
11         delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
12         break;
13       default:
14         throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
15     }
16 
17   }

可以看出來是根據ms儲存的,三張就是Statement的三種,我們直接看預編譯的,PreparedStatementHandler

實際上一些公共方法在BaseStatementHandler實現了

 1   public Statement prepare(Connection connection) throws SQLException {
 2     ErrorContext.instance().sql(boundSql.getSql());
 3     Statement statement = null;
 4     try {
 5       statement = instantiateStatement(connection);
 6       setStatementTimeout(statement);
 7       setFetchSize(statement);
 8       return statement;
 9     } catch (SQLException e) {
10       closeStatement(statement);
11       throw e;
12     } catch (Exception e) {
13       closeStatement(statement);
14       throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
15     }
16   }

instantiateStatement子類PreparedStatementHandler實現

 1   protected Statement instantiateStatement(Connection connection) throws SQLException {
 2     String sql = boundSql.getSql();
 3     if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
 4       String[] keyColumnNames = mappedStatement.getKeyColumns();
 5       if (keyColumnNames == null) {
 6         return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
 7       } else {
 8         return connection.prepareStatement(sql, keyColumnNames);
 9       }
10     } else if (mappedStatement.getResultSetType() != null) {
11       return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
12     } else {
13       return connection.prepareStatement(sql);
14     }
15   }

上面就是根據mappedStatement的resultType不同建立不同構造器的Statement;

下面來看下引數是怎麼設定的。PreparedStatementHandler,但是handler是裡面的paramterHandler是什麼實現類呢?什麼時候注入的呢?

1   public void parameterize(Statement statement) throws SQLException {
2     parameterHandler.setParameters((PreparedStatement) statement);
3   }

來看下BaseStatementHandler的構造器

 1   protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
 2     this.configuration = mappedStatement.getConfiguration();
 3     this.executor = executor;
 4     this.mappedStatement = mappedStatement;
 5     this.rowBounds = rowBounds;
 6 
 7     this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
 8     this.objectFactory = configuration.getObjectFactory();
 9 
10     if (boundSql == null) { // issue #435, get the key before calculating the statement
11       generateKeys(parameterObject);
12       boundSql = mappedStatement.getBoundSql(parameterObject);
13     }
14 
15     this.boundSql = boundSql;
16     //都說是相當於註冊引數處理器,結果集處理器了。下面看預設的引數處理器是啥
17     this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
18     this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
19   }
1   public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
//可以看出來就是從mappenStatement的語言註冊器建立引數處理器。實際上就一個語言處理器。
2 ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql); 3 parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); 4 return parameterHandler; 5 }

預設的就是XMLLanguageDriver

1 public class XMLLanguageDriver implements LanguageDriver {
2 
3   @Override
4   public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
5     return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
6   }

接下來就看DefaultParameterHandler怎麼實現setParameters()

 1   @Override
 2   public void setParameters(PreparedStatement ps) {
 3     ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
 4     List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
 5     if (parameterMappings != null) {
 6       for (int i = 0; i < parameterMappings.size(); i++) {
 7         ParameterMapping parameterMapping = parameterMappings.get(i);
 8         if (parameterMapping.getMode() != ParameterMode.OUT) {
 9           Object value;
10           String propertyName = parameterMapping.getProperty();
11           if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
12             value = boundSql.getAdditionalParameter(propertyName);
13           } else if (parameterObject == null) {
14             value = null;
15           } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
16             value = parameterObject;
17           } else {
18             MetaObject metaObject = configuration.newMetaObject(parameterObject);
19             value = metaObject.getValue(propertyName);
20           }
21           TypeHandler typeHandler = parameterMapping.getTypeHandler();
22           JdbcType jdbcType = parameterMapping.getJdbcType();
23           if (value == null && jdbcType == null) {
//這裡有bug 如果傳入值為0 也沒設定引數jdbctype 會報錯,這塊可以給根據javaType給預設的型別
24 jdbcType = configuration.getJdbcTypeForNull(); 25 } 26 try { 27 typeHandler.setParameter(ps, i + 1, value, jdbcType); 28 } catch (TypeException e) { 29 throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); 30 } catch (SQLException e) { 31 throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); 32 } 33 } 34 } 35 } 36 }

這塊就很簡單了 根據每個引數JavaType jdbctype設設定。到此為止 prepareStatement的引數就都設定完了。

來看下 查詢return handler.<E>query(stmt, resultHandler);

實際上也是PreparedStatementHandler實現的

1   @Override
2   public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
3     PreparedStatement ps = (PreparedStatement) statement;
4     ps.execute();
//執行就不說了,就看下面 使用結果處理器來處理結果集 返回一個List
5 return resultSetHandler.<E> handleResultSets(ps); 6 }

resultSetHandler在父類構造器初始化的。看下預設的是什麼吧

1   public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
2       ResultHandler resultHandler, BoundSql boundSql) {
3     ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
4     resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
5     return resultSetHandler;
6   }
 1 public List<Object> handleResultSets(Statement stmt) throws SQLException {
 2     ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
 3 
 4     final List<Object> multipleResults = new ArrayList<Object>();
 5 
 6     int resultSetCount = 0;
//ResultSet的包裝類ResultSet,同時獲取資料庫的MetaData資料,包括資料表列名、列的型別、類序號等
7 ResultSetWrapper rsw = getFirstResultSet(stmt); 8 9 List<ResultMap> resultMaps = mappedStatement.getResultMaps(); 10 int resultMapCount = resultMaps.size(); 11 validateResultMapsCount(rsw, resultMapCount); 12 while (rsw != null && resultMapCount > resultSetCount) { 13 ResultMap resultMap = resultMaps.get(resultSetCount); 14 handleResultSet(rsw, resultMap, multipleResults, null); 15 rsw = getNextResultSet(stmt); 16 cleanUpAfterHandlingResultSet(); 17 resultSetCount++; 18 } 19 20 String[] resultSets = mappedStatement.getResulSets(); 21 if (resultSets != null) { 22 while (rsw != null && resultSetCount < resultSets.length) { 23 ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]); 24 if (parentMapping != null) { 25 String nestedResultMapId = parentMapping.getNestedResultMapId(); 26 ResultMap resultMap = configuration.getResultMap(nestedResultMapId); 27 handleResultSet(rsw, resultMap, null, parentMapping); 28 } 29 rsw = getNextResultSet(stmt); 30 cleanUpAfterHandlingResultSet(); 31 resultSetCount++; 32 } 33 } 34 35 return collapseSingleResultList(multipleResults); 36 }
 1   private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
 2     try {
 3       if (parentMapping != null) {
 4         handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
 5       } else {
 6         if (resultHandler == null) {
 7           DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
 8           handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
 9           multipleResults.add(defaultResultHandler.getResultList());
10         } else {
11           handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
12         }
13       }
14     } finally {
15       // issue #228 (close resultsets)
16       closeResultSet(rsw.getResultSet());
17     }
18   }
1   private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
2     if (resultMap.hasNestedResultMaps()) {
3       ensureNoRowBounds();
4       checkResultHandler();
//巢狀結果集
5 handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); 6 } else {
//簡單的結果集
7 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); 8 } 9 }
 1   private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
 2       throws SQLException {
 3     DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
 4     skipRows(rsw.getResultSet(), rowBounds);
 5     while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
 6       ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
 7       Object rowValue = getRowValue(rsw, discriminatedResultMap); //獲取每一行的值
 8       storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
 9     }
10   }
 1   private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
 2     final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//建立資料物件的類物件 //todo這一塊好複雜,有時間但單獨在分析。
3 Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null); 4 if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) { 5 final MetaObject metaObject = configuration.newMetaObject(resultObject); 6 boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty(); 7 if (shouldApplyAutomaticMappings(resultMap, false)) {
//這一塊就是為這個物件挨個賦值了
8 foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; 9 } 10 foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; 11 foundValues = lazyLoader.size() > 0 || foundValues; 12 resultObject = foundValues ? resultObject : null; 13 return resultObject; 14 } 15 return resultObject; 16 }
 1   private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
 2     List<UnMappedColumAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
 3     boolean foundValues = false;
 4     if (autoMapping.size() > 0) {
//遍歷表的每一項 給物件賦值。
5 for (UnMappedColumAutoMapping mapping : autoMapping) {
//根據對應的java型別呼叫不同getResult獲取值 如String, getString(); Int getInt()
6 final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column); 7 // issue #377, call setter on nulls 8 if (value != null || configuration.isCallSettersOnNulls()) { 9 if (value != null || !mapping.primitive) { 10 metaObject.setValue(mapping.property, value); 11 } 12 foundValues = true; 13 } 14 } 15 } 16 return foundValues; 17 }

到此為止,整個過程結束,結果集封裝理解不是特別多,還有就是其中一些細節要以後慢慢推敲。如果有的地方解釋的不對的地方希望看到的能及時提出探討,萬分感謝