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