一羊异、簡(jiǎn)單介紹下 SqlSession
- SqlSession 是?個(gè)接口,它有兩個(gè)實(shí)現(xiàn)類:DefaultSqlSession(默認(rèn))和
SqlSessionManager(棄用捉撮,不做介紹) - SqlSession 是 MyBatis 中用于和數(shù)據(jù)庫(kù)交互的頂層類怕品,通常將它與 ThreadLocal 綁定,?個(gè)會(huì)話使用?個(gè) SqlSession巾遭,并且在使用完畢后需要 close
- SqlSession 中的兩個(gè)最重要的參數(shù)肉康,configuration 與初始化時(shí)的相同闯估,Executor 為執(zhí)行器
public class DefaultSqlSession implements SqlSession { private final Configuration configuration; private final Executor executor; }
-
Executor
Executor 也是?個(gè)接口,他有三個(gè)常用的實(shí)現(xiàn)類:- BatchExecutor(重用語(yǔ)句并執(zhí)行批量更新)
- ReuseExecutor(重用預(yù)處理語(yǔ)句 prepared statements)
- SimpleExecutor(普通的執(zhí)行器吼和,默認(rèn))
二涨薪、生產(chǎn) DefaultSqlSession 實(shí)例對(duì)象,設(shè)置了事務(wù)不自動(dòng)提交纹安,完成了 executor 對(duì)象的創(chuàng)建
- 入口
// 生產(chǎn)了DefaultSqlsession實(shí)例對(duì)象 設(shè)置了事務(wù)不自動(dòng)提交 完成了 executor 對(duì)象的創(chuàng)建 SqlSession sqlSession = sqlSessionFactory.openSession();
-
openSession()
中傳遞三個(gè)參數(shù)尤辱,第一個(gè)為默認(rèn)的執(zhí)行器 SimpleExecutor,第二個(gè)表示事務(wù)隔離級(jí)別厢岂,最后一個(gè)參數(shù)表示是否自動(dòng)提交事務(wù)光督,所以一會(huì)生產(chǎn)出來的 SqlSession,它需要手動(dòng)提交事務(wù)@Override public SqlSession openSession() { //getDefaultExecutorType()傳遞的是SimpleExecutor // 第二個(gè)參數(shù)表示 當(dāng)前數(shù)據(jù)庫(kù)事務(wù)的隔離級(jí)別 // 最后一個(gè)參數(shù)表示是否自動(dòng)提交事務(wù) return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } public ExecutorType getDefaultExecutorType() { return defaultExecutorType; } protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
-
openSessionFromDataSource()
方法//進(jìn)入openSessionFromDataSource塔粒。 //ExecutorType 為Executor的類型结借,TransactionIsolationLevel為事務(wù)隔離級(jí)別,autoCommit是否開啟事務(wù) //openSession的多個(gè)重載方法可以指定獲得的SeqSession的Executor類型和事務(wù)的處理 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 獲得 Environment 對(duì)象 final Environment environment = configuration.getEnvironment(); // 創(chuàng)建 Transaction 對(duì)象 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 創(chuàng)建 Executor 對(duì)象 final Executor executor = configuration.newExecutor(tx, execType); // 創(chuàng)建 DefaultSqlSession 對(duì)象 return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { // 如果發(fā)生異常卒茬,則關(guān)閉 Transaction 對(duì)象 closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
- 開始使用 SqlSession船老,根據(jù) statementId 來從 configuration 中的 map 集合中獲取到了指定的 MappedStatement 對(duì)象,并將查詢?nèi)蝿?wù)委派給了 executor 執(zhí)行器
//進(jìn)入selectList方法圃酵,多個(gè)重載方法 @Override public <E> List<E> selectList(String statement) { return this.selectList(statement, null); } @Override public <E> List<E> selectList(String statement, Object parameter) { return this.selectList(statement, parameter, RowBounds.DEFAULT); } @Override public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { // 獲得 MappedStatement 對(duì)象 MappedStatement ms = configuration.getMappedStatement(statement); // 執(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(); } }
三柳畔、Executor
- 先點(diǎn)進(jìn)
executor.query()
方法,發(fā)現(xiàn)真正的實(shí)現(xiàn)類是 BaseExecutor郭赐,他是 SimpleExecutor 的父類//此方法在SimpleExecutor的父類BaseExecutor中實(shí)現(xiàn) @Override public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //根據(jù)傳入的參數(shù)動(dòng)態(tài)獲得SQL語(yǔ)句薪韩,最后返回用BoundSql對(duì)象表示 BoundSql boundSql = ms.getBoundSql(parameter); //為本次查詢創(chuàng)建緩存的Key CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); // 查詢 return query(ms, parameter, rowBounds, resultHandler, key, boundSql); }
- 繼續(xù)點(diǎn)擊
@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()); // 已經(jīng)關(guān)閉,則拋出 ExecutorException 異常 if (closed) { throw new ExecutorException("Executor was closed."); } // 清空本地緩存捌锭,如果 queryStack 為零俘陷,并且要求清空本地緩存。 if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { // queryStack + 1 queryStack++; // 從一級(jí)緩存中观谦,獲取查詢結(jié)果 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; // 獲取到拉盾,則進(jìn)行處理 if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); // 獲得不到,則從數(shù)據(jù)庫(kù)中查詢 } else { list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { // queryStack - 1 queryStack--; } if (queryStack == 0) { // 執(zhí)行延遲加載 for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 // 清空 deferredLoads deferredLoads.clear(); // 如果緩存級(jí)別是 LocalCacheScope.STATEMENT 豁状,則進(jìn)行清理 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; }
- 查詢數(shù)據(jù)庫(kù)的方法
// 從數(shù)據(jù)庫(kù)中讀取操作 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; // 在緩存中捉偏,添加占位對(duì)象。此處的占位符泻红,和延遲加載有關(guān)告私,可見 `DeferredLoad#canLoad()` 方法 localCache.putObject(key, EXECUTION_PLACEHOLDER); try { // 執(zhí)行讀操作 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { // 從緩存中,移除占位對(duì)象 localCache.removeObject(key); } // 添加到緩存中 localCache.putObject(key, list); // 暫時(shí)忽略承桥,存儲(chǔ)過程相關(guān) if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }
- 將 JDBC 查詢代碼再次委派給 StatementHandler 去執(zhí)行
@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(); // 傳入?yún)?shù)創(chuàng)建StatementHanlder對(duì)象來執(zhí)行查詢 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 創(chuàng)建jdbc中的statement對(duì)象 stmt = prepareStatement(handler, ms.getStatementLog()); // 執(zhí)行 StatementHandler 驻粟,進(jìn)行讀操作 return handler.query(stmt, resultHandler); } finally { // 關(guān)閉 StatementHandler 對(duì)象 closeStatement(stmt); } } // 初始化 StatementHandler 對(duì)象 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; // 獲得 Connection 對(duì)象 Connection connection = getConnection(statementLog); // 創(chuàng)建 Statement 或 PrepareStatement 對(duì)象 stmt = handler.prepare(connection, transaction.getTimeout()); // 設(shè)置 SQL 上的參數(shù),例如 PrepareStatement 對(duì)象上的占位符 handler.parameterize(stmt); return stmt; }
四、StatementHandler
- StatementHandler 對(duì)象主要完成兩個(gè)工作
- 對(duì)于 JDBC 的 PreparedStatement 類型的對(duì)象蜀撑,創(chuàng)建的過程中挤巡,我們使用的是SQL語(yǔ)句字符串會(huì)包含若干個(gè) "?" 占位符,我們其后再對(duì)占位符進(jìn)行設(shè)值酷麦。StatementHandler 通過
parameterize(statement)
方法對(duì) S tatement 進(jìn)行設(shè)值 - StatementHandler 通過
List query(Statement statement, ResultHandler resultHandler)
方法來完成執(zhí)行 Statement矿卑,和將 Statement 對(duì)象返回的 resultSet 封裝成 List
- 對(duì)于 JDBC 的 PreparedStatement 類型的對(duì)象蜀撑,創(chuàng)建的過程中挤巡,我們使用的是SQL語(yǔ)句字符串會(huì)包含若干個(gè) "?" 占位符,我們其后再對(duì)占位符進(jìn)行設(shè)值酷麦。StatementHandler 通過
- 進(jìn)入
handler.parameterize(stmt);
@Override public void parameterize(Statement statement) throws SQLException { //使用ParameterHandler對(duì)象來完成對(duì)Statement的設(shè)值 parameterHandler.setParameters((PreparedStatement) statement); } @Override public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); // 遍歷 ParameterMapping 數(shù)組 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { // 獲得 ParameterMapping 對(duì)象 ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { // 獲得值 Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params 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、jdbcType 屬性 TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } // 設(shè)置 ? 占位符的參數(shù) try { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException | SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
- 回到 SimpleExecutor 的
doQuery()
方法中沃饶,繼續(xù)進(jìn)入handler.query(stmt, resultHandler);
@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(); // 傳入?yún)?shù)創(chuàng)建StatementHanlder對(duì)象來執(zhí)行查詢 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 創(chuàng)建jdbc中的statement對(duì)象 stmt = prepareStatement(handler, ms.getStatementLog()); // 執(zhí)行 StatementHandler 母廷,進(jìn)行讀操作 return handler.query(stmt, resultHandler); } finally { // 關(guān)閉 StatementHandler 對(duì)象 closeStatement(stmt); } } @Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; // 執(zhí)行查詢 ps.execute(); // 處理返回結(jié)果 return resultSetHandler.handleResultSets(ps); }
- 處理返回結(jié)果集
@Override public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); // 多 ResultSet 的結(jié)果集合,每個(gè) ResultSet 對(duì)應(yīng)一個(gè) Object 對(duì)象糊肤。而實(shí)際上琴昆,每個(gè) Object 是 List<Object> 對(duì)象。 // 在不考慮存儲(chǔ)過程的多 ResultSet 的情況馆揉,普通的查詢业舍,實(shí)際就一個(gè) ResultSet ,也就是說升酣,multipleResults 最多就一個(gè)元素舷暮。 final List<Object> multipleResults = new ArrayList<>(); int resultSetCount = 0; // 獲得首個(gè) ResultSet 對(duì)象,并封裝成 ResultSetWrapper 對(duì)象 ResultSetWrapper rsw = getFirstResultSet(stmt); // 獲得 ResultMap 數(shù)組 // 在不考慮存儲(chǔ)過程的多 ResultSet 的情況噩茄,普通的查詢下面,實(shí)際就一個(gè) ResultSet ,也就是說绩聘,resultMaps 就一個(gè)元素沥割。 List<ResultMap> resultMaps = mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); // 校驗(yàn) while (rsw != null && resultMapCount > resultSetCount) { // 獲得 ResultMap 對(duì)象 ResultMap resultMap = resultMaps.get(resultSetCount); // 處理 ResultSet ,將結(jié)果添加到 multipleResults 中 handleResultSet(rsw, resultMap, multipleResults, null); // 獲得下一個(gè) ResultSet 對(duì)象君纫,并封裝成 ResultSetWrapper 對(duì)象 rsw = getNextResultSet(stmt); // 清理 cleanUpAfterHandlingResultSet(); // resultSetCount ++ resultSetCount++; } // 因?yàn)?`mappedStatement.resultSets` 只在存儲(chǔ)過程中使用,本系列暫時(shí)不考慮芹彬,忽略即可 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++; } } // 如果是 multipleResults 單元素蓄髓,則取首元素返回 return collapseSingleResultList(multipleResults); }
// 處理 ResultSet ,將結(jié)果添加到 multipleResults 中 private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException { try { // 暫時(shí)忽略舒帮,因?yàn)橹挥写鎯?chǔ)過程的情況会喝,調(diào)用該方法,parentMapping 為非空 if (parentMapping != null) { handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping); } else { // 如果沒有自定義的 resultHandler 玩郊,則創(chuàng)建默認(rèn)的 DefaultResultHandler 對(duì)象 if (resultHandler == null) { // 創(chuàng)建 DefaultResultHandler 對(duì)象 DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); // 處理 ResultSet 返回的每一行 Row handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); // 添加 defaultResultHandler 的處理的結(jié)果肢执,到 multipleResults 中 multipleResults.add(defaultResultHandler.getResultList()); } else { // 處理 ResultSet 返回的每一行 Row handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) // 關(guān)閉 ResultSet 對(duì)象 closeResultSet(rsw.getResultSet()); } }
// 處理 ResultSet 返回的每一行 Row public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { // 處理嵌套映射的情況 if (resultMap.hasNestedResultMaps()) { // 校驗(yàn)不要使用 RowBounds ensureNoRowBounds(); // 校驗(yàn)不要使用自定義的 resultHandler checkResultHandler(); // 處理嵌套映射的結(jié)果 handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); // 處理簡(jiǎn)單映射的情況 } else { // 處理簡(jiǎn)單映射的結(jié)果 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } }