objects = sqlSession.selectList("namespace.id"); // 4.(1)根據statementid來從Configuration中map集合中獲取到了指定的MappedStatement對象
//(2)將查詢任務委派了executor執行器
List<Object> objects = sqlSession.selectList("namespace.id");
//DefaultSqlSession.java
@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 statementId, Object parameter, RowBounds rowBounds) {
try {
// 獲得 MappedStatement 對象
MappedStatement ms = configuration.getMappedStatement(statement);
// 執行查詢
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();
}
}
我們在生產DefaultSqlsession實例對象的時候傳入了configuration,而這一步就是從configuration對象中根據statementId取出MappedStatement對象(MappedStatement 封裝了這條SQL的一些信息)
然后執行executor.query() 方法,把查詢任務委派給執行器executor
3. executor.query() return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
//↓↓↓↓↓↓↓↓
// 查詢,帶 ResultHandler
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
//↓↓↓↓↓↓↓↓
//此方法在SimpleExecutor的父類BaseExecutor中實現
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//根據傳入的參數動態獲得SQL語句,最后返回用BoundSql對象表示
BoundSql boundSql = ms.getBoundSql(parameter);
//為本次查詢創建緩存的Key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// 查詢
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@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());
// 已經關閉,則拋出 ExecutorException 異常
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 清空本地緩存,如果 queryStack 為零,並且要求清空本地緩存。
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
// queryStack + 1
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 - 1
queryStack--;
}
if (queryStack == 0) {
// 執行延遲加載
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
// 清空 deferredLoads
deferredLoads.clear();
// 如果緩存級別是 LocalCacheScope.STATEMENT ,則進行清理
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
queryFromDatabase // 從數據庫中讀取操作
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
// 在緩存中,添加占位對象。此處的占位符,和延遲加載有關,可見 `DeferredLoad#canLoad()` 方法
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;
}
doQuery @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();
// 傳入參數創建StatementHanlder對象來執行查詢
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 創建jdbc中的statement對象
stmt = prepareStatement(handler, ms.getStatementLog());
// 執行 StatementHandler ,進行讀操作
return handler.query(stmt, resultHandler);
} finally {
// 關閉 StatementHandler 對象
closeStatement(stmt);
}
}
prepareStatement() // 初始化 StatementHandler 對象
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 獲得 Connection 對象
Connection connection = getConnection(statementLog);
// 創建 Statement 或 PrepareStatement 對象
stmt = handler.prepare(connection, transaction.getTimeout());
// 設置 SQL 上的參數,例如 PrepareStatement 對象上的占位符
handler.parameterize(stmt);
return stmt;
}
4.StatementHandler
StatementHandler對象主要完成兩個工作:設置參數(prepareStatement),解析返回結果集(resultSetHandler)
對於JDBC的PreparedStatement類型的對象,創建的過程中,我們使用的是SQL語句字符串會包含若干個?占位符,我們其后再對占位符進行設值。
StatementHandler通過parameterize(statement)方法對 Statement 進行設值;
StatementHandler 通過 List query(Statement statement, ResultHandler resultHandler)方法來完成執行Statement,和將Statement對象返回的resultSet封裝成List;
在哪里設置參數?
在prepareStatement方法中有一句話:
handler.parameterize(stmt);
//PreparedStatementHandler.java
@Override
public void parameterize(Statement statement) throws SQLException {
//使用ParameterHandler對象來完成對Statement的設值
parameterHandler.setParameters((PreparedStatement) statement);
}
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
// 遍歷 ParameterMapping 數組
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
// 獲得 ParameterMapping 對象
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();
}
// 設置 ? 占位符的參數
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);
}
}
}
}
}
typeHandler.setParameter(ps, i + 1, value, jdbcType);
可以看到,我們實際設置參數是通過parameterHandler設值的。並且調用了 typeHandler.setParameter()方法來給?賦值。同時指定了jdbcType。
回到doQuery()方法,進入到handler.query(stmt, resultHandler)方法,找到其實現類PreparedStatementHandler
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 執行查詢
ps.execute();
// 處理返回結果
return resultSetHandler.handleResultSets(ps);
}
如何處理結果集?
進入 return resultSetHandler.handleResultSets(ps)
//
// HANDLE RESULT SETS
//
// 處理 {@link java.sql.ResultSet} 結果集
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
// 多 ResultSet 的結果集合,每個 ResultSet 對應一個 Object 對象。而實際上,每個 Object 是 List<Object> 對象。
// 在不考慮存儲過程的多 ResultSet 的情況,普通的查詢,實際就一個 ResultSet ,也就是說,multipleResults 最多就一個元素。
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 獲得首個 ResultSet 對象,並封裝成 ResultSetWrapper 對象
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 獲得 ResultMap 數組
// 在不考慮存儲過程的多 ResultSet 的情況,普通的查詢,實際就一個 ResultSet ,也就是說,resultMaps 就一個元素。
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount); // 校驗
while (rsw != null && resultMapCount > resultSetCount) {
// 獲得 ResultMap 對象
ResultMap resultMap = resultMaps.get(resultSetCount);
// 處理 ResultSet ,將結果添加到 multipleResults 中
handleResultSet(rsw, resultMap, multipleResults, null);
// 獲得下一個 ResultSet 對象,並封裝成 ResultSetWrapper 對象
rsw = getNextResultSet(stmt);
// 清理
cleanUpAfterHandlingResultSet();
// resultSetCount ++
resultSetCount++;
}
// 因為 `mappedStatement.resultSets` 只在存儲過程中使用,本系列暫時不考慮,忽略即可
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 對象,封裝成 ResultSetWrapper 對象
*
* @param stmt Statement 對象
* @return ResultSetWrapper 對象
*/
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
ResultSet rs = stmt.getResultSet();
// 可以忽略
while (rs == null) {
// move forward to get the first resultset in case the driver
// doesn't return the resultset as the first result (HSQLDB 2.1)
if (stmt.getMoreResults()) {
rs = stmt.getResultSet();
} else {
if (stmt.getUpdateCount() == -1) {
// no more results. Must be no resultset
break;
}
}
}
// 將 ResultSet 對象,封裝成 ResultSetWrapper 對象
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
// 處理 ResultSet ,將結果添加到 multipleResults 中
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
// 暫時忽略,因為只有存儲過程的情況,調用該方法,parentMapping 為非空
if (parentMapping != null) {
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
// 如果沒有自定義的 resultHandler ,則創建默認的 DefaultResultHandler 對象
if (resultHandler == null) {
// 創建 DefaultResultHandler 對象
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
// 處理 ResultSet 返回的每一行 Row
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 添加 defaultResultHandler 的處理的結果,到 multipleResults 中
multipleResults.add(defaultResultHandler.getResultList());
} else {
// 處理 ResultSet 返回的每一行 Row
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
// 關閉 ResultSet 對象
closeResultSet(rsw.getResultSet());
}
}