Handler
參數(shù)處理
Mybatis對(duì)接口實(shí)參的解析發(fā)生在創(chuàng)建Statement之前,對(duì)接口參數(shù)解析結(jié)果如下:
單個(gè)參數(shù) : 直接將調(diào)用接口傳入的實(shí)參返回惕艳,不需要進(jìn)一步解析
多個(gè)參數(shù):多個(gè)參數(shù)的情況下,會(huì)將參數(shù)轉(zhuǎn)換成【參數(shù)名 -> 實(shí)參值】的映射關(guān)系Map
若接口形參使用了@Param參數(shù),使用@Param參數(shù)指定的名稱
若接口形參未使用@Param參數(shù)稚晚,JDK8以上可通過(guò)參數(shù)-parameters打開形參名稱解析,未打開則解析結(jié)果為arg0型诚、arg1...形式的【映射關(guān)系】
Mybatis還會(huì)為每個(gè)接口形參根據(jù)其位置生成一個(gè)兜底的param0客燕、param1...形式的【映射關(guān)系】
ParamNameResolver
類的功能是解析Mapper接口入?yún)⒚Q,解析參數(shù)的時(shí)機(jī)為:
public class MapperMethod {
// ...
private final SqlCommand command; // 當(dāng)前要操作的SQL標(biāo)簽狰贯,為在Mapper.xml文件中使用的<select><update><delete><insert>標(biāo)簽
private final MethodSignature method; // 記錄mapper接口命名標(biāo)記信息
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
// ...
case SELECT:
// ...
// 使用ParamNameResolver開始解析方法調(diào)用的【形參名->實(shí)參值】映射關(guān)系
// 當(dāng)方法僅有一個(gè)形參時(shí)也搓,param即為方法傳入實(shí)參
// 當(dāng)方法有多個(gè)形參是,param為Map類型涵紊,記錄【形參名->實(shí)參值】映射關(guān)系
Object param = method.convertArgsToSqlCommandParam(args);
// 集成Spring時(shí)傍妒,當(dāng)前的SqlSession對(duì)象為SqlTemplate類對(duì)象
result = sqlSession.selectOne(command.getName(), param);
break;
// ...
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
// ...
return result;
}
}
解析接口名稱類ParamNameResolver
如下:
public class ParamNameResolver {
private static final String GENERIC_NAME_PREFIX = "param";
private final SortedMap<Integer, String> names; // 記錄解析得到的入?yún)⒚Q,映射關(guān)系為【參數(shù)位置 -> 參數(shù)名稱】
private boolean hasParamAnnotation; // 標(biāo)記該方法是否使用了@Param注解
// ...
public ParamNameResolver(Configuration config, Method method) {
// 獲取接口參數(shù)類型數(shù)組
final Class<?>[] paramTypes = method.getParameterTypes();
// 獲取接口每個(gè)參數(shù)的注解摸柄,由于參數(shù)前可以采用多個(gè)注解颤练,因此使用二維數(shù)組
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
// 記錄方法參數(shù)個(gè)數(shù),使用paramTypes數(shù)組長(zhǎng)度也一樣驱负,如果沒(méi)有被注解修飾的參數(shù)也會(huì)作為一個(gè)空數(shù)組放入這個(gè)二維數(shù)組
int paramCount = paramAnnotations.length;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
// 若當(dāng)前參數(shù)類型為RowBounds或者ResultHandler不處理
if (isSpecialParameter(paramTypes[paramIndex])) {
continue;
}
String name = null;
// 遍歷每一個(gè)參數(shù)的注解嗦玖,查詢是否使用了@Param注解,獲取@Param上面的name屬性
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
if (config.isUseActualParamName()) {
// 將入?yún)⒔馕鰹閍rg0跃脊、arg1格式的名稱
// jdk8(含)以上版本宇挫,可以在編譯類的時(shí)候使用 -parameters 命令,那么就可以獲取方法參數(shù)的名稱
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// 直接使用數(shù)字0,1,2作為入?yún)⒚Q
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
/**
* 解析接口參數(shù)名稱
* @param args 調(diào)用本接口的實(shí)參
* @return 使用Object類型返回酪术,方法僅有一個(gè)形參時(shí)返回入?yún)?duì)象捞稿,有多個(gè)形參是,返回【形參名->實(shí)參值】映射關(guān)系Map對(duì)象
**/
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
// 如果調(diào)用接口實(shí)參為null 或 從接口上解析得到的參數(shù)個(gè)數(shù)為0
if (args == null || paramCount == 0) {
return null;
}
// 如果沒(méi)有使用@Param注解且參數(shù)就一個(gè)拼缝,直接返回傳入的實(shí)參即可
else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
final Map<String, Object> param = new ParamMap<Object>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
// 保存參數(shù)名稱 -> 實(shí)參值 映射關(guān)系
param.put(entry.getValue(), args[entry.getKey()]);
// 生成一個(gè)當(dāng)前位置參數(shù)名稱娱局,格式為param1.....
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// 若不存在這個(gè)格式的參數(shù)名稱,額外保存param1 -> 實(shí)參值 的映射關(guān)系
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
// 最終返回的一定有param1 -> 實(shí)參值的映射
// 以下兩種映射每個(gè)參數(shù)必存在一種
// arg0 -> 實(shí)參
// @Param注解定義名稱 -> 實(shí)參
return param;
}
}
}
StatementHandler
JDBC處理器咧七,基于JDBC構(gòu)建Statement并設(shè)置參數(shù)衰齐,然后執(zhí)行SQL。每調(diào)用會(huì)話當(dāng)中一次SQL继阻,都會(huì)有與之相對(duì)應(yīng)的且唯一的Statement實(shí)例耻涛。
PreparedStatementHandler
相對(duì)來(lái)說(shuō)废酷,PreparedStatement的應(yīng)用場(chǎng)景是所有Statement中應(yīng)用最多的,這里以其對(duì)應(yīng)的PreparedStatementHandler為例進(jìn)行學(xué)習(xí)抹缕。
創(chuàng)建PreparedStatement
public class SimpleExecutor extends BaseExecutor {
// ...
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
// 通過(guò)Configuration創(chuàng)建StatementHandler澈蟆,然后由StatementHandler創(chuàng)建Statement
// 這里以PreparedStatementHandler創(chuàng)建PreparedStatement為例
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds,
resultHandler, boundSql);
// 擁有了PreparedStatementHandler之后,創(chuàng)建PreparedStatement
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
}
// 通過(guò)PreparedStatementHandler之后卓研,創(chuàng)建PreparedStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
// 通過(guò)BaseStatementHandler創(chuàng)建PreparedStatement
stmt = handler.prepare(connection, transaction.getTimeout());
// 為PreparedStatement的占位符?設(shè)置參數(shù)
handler.parameterize(stmt);
return stmt;
}
}
// 展示SimpleExecutor類中通過(guò)Configuration創(chuàng)建PreparedStatement的相關(guān)方法
public class Configuration {
// ...
// 通過(guò)Configuration創(chuàng)建StatementHandler
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 = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
}
// Configuration通過(guò)RoutingStatementHandler創(chuàng)建不同種類的StatementHandler趴俘,主要根據(jù)MappedStatement配置屬性StatementType決定
public class RoutingStatementHandler implements StatementHandler {
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) {
// 根據(jù)MappedStatement的配置信息,選擇創(chuàng)建不同的Statement
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
// ...
}
// PreparedStatementHandler創(chuàng)建PreparedStatement對(duì)象奏赘,通過(guò)調(diào)用父類BaseStatementHandler抽取的共同方法prepare實(shí)現(xiàn)
public abstract class BaseStatementHandler implements StatementHandler {
// 創(chuàng)建Statement對(duì)象
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// instantiateStatement是個(gè)抽象方法寥闪,由子類StatementHandler、PreparedStatementHandler磨淌、CallableStatementHandler實(shí)現(xiàn)
statement = instantiateStatement(connection);
setStatementTimeout(statement, transactionTimeout);
setFetchSize(statement);
return statement;
} catch (SQLException e) {
// ...
} catch (Exception e) {
// ...
}
}
}
public class PreparedStatementHandler extends BaseStatementHandler {
// ...
// 實(shí)現(xiàn)父類BaseStatementHandler中的抽象方法instantiateStatement疲憋,創(chuàng)建PreparedStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
}
ParameterHandler
通過(guò)TypeHandler為PreparedStatement設(shè)置參數(shù)
public class ReuseExecutor extends BaseExecutor {
// ...
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
// 創(chuàng)建好PreparedStatement之后,為其設(shè)置參數(shù)
handler.parameterize(stmt);
return stmt;
}
}
public class PreparedStatementHandler extends BaseStatementHandler {
// ...
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
// 設(shè)置參數(shù)處理器梁只,有且僅有此實(shí)現(xiàn)
public class DefaultParameterHandler implements ParameterHandler {
// ...
public void setParameters(PreparedStatement ps) {
// 得到Sql的相關(guān)參數(shù)信息缚柳,內(nèi)含TypeHandler,JdbcType搪锣,JavaType
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
// 不是存儲(chǔ)過(guò)程的OUT參數(shù)
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
}
// Mapper接口沒(méi)有形參秋忙,也就沒(méi)有實(shí)參,直接將要設(shè)置的value值賦值為null
else if (parameterObject == null) {
value = null;
}
// 檢查是否有TypeHandler可以處理當(dāng)前接口實(shí)參類型淤翔,符合這個(gè)方法的話表示當(dāng)前接口方法僅有一個(gè)形參且為基本類型翰绊,
// 否則parameterObject為Map類型
// TypeHandlerRegistry記錄了 JavaType -> JdbcType -> TypeHandler 的映射關(guān)系,
// 存在 JavaType -> null -> TypeHandler 的映射關(guān)系旁壮,表示該java類型沒(méi)有指定jdbc類型默認(rèn)使用的TypeHandler
else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
// TODO 這個(gè)metaObject對(duì)象為什么不直接作為本方法的全局變量????
// TODO 如果parameterObject為Map<String,Object>類型监嗜、非簡(jiǎn)單類型,不是每次都需要重新解析???
// MetaObject可以通過(guò)反射獲取Map<String,Object>以及用戶自定義對(duì)象屬性的值
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 通過(guò)TypeHandler為PreparedStatement設(shè)置占位符實(shí)參
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
// ...
}
}
}
}
}
}
ResultSetHandler
執(zhí)行數(shù)據(jù)庫(kù)查詢抡谐,處理返回的結(jié)果集
public class SimpleExecutor extends BaseExecutor {
// ...
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());
// 通過(guò)PreparedStatementHandler執(zhí)行數(shù)據(jù)庫(kù)查詢操作
return handler.query(stmt, resultHandler);
} finally {
// 關(guān)閉PreparedStatement
closeStatement(stmt);
}
}
}
// 通過(guò)PreparedStatementHandler觸發(fā)數(shù)據(jù)庫(kù)操作
public class PreparedStatementHandler extends BaseStatementHandler {
// ...
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 調(diào)用JDBC的PreparedStatement#execute執(zhí)行數(shù)據(jù)庫(kù)操作
ps.execute();
// 使用ResultSetHandler處理返回的結(jié)果集ResultSet
return resultSetHandler.handleResultSets(ps);
}
}
// 使用ResultSetHandler處理返回結(jié)果集ResultSet
public class DefaultResultSetHandler implements ResultSetHandler {
// ...
public List<Object> handleResultSets(Statement stmt) throws SQLException {
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 獲取第一個(gè)結(jié)果集裁奇,由于存儲(chǔ)過(guò)程可能有多個(gè)出參,存在多個(gè)結(jié)果集返回的情況
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
// 開始處理結(jié)果集(下有源碼細(xì)節(jié))
handleResultSet(rsw, resultMap, multipleResults, null);
// 處理下一個(gè)結(jié)果集麦撵,存儲(chǔ)過(guò)程用的很少刽肠,這里大多數(shù)時(shí)候都是僅僅處理一個(gè)結(jié)果集就好了
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
// ...
// 由于存在存儲(chǔ)過(guò)程有多個(gè)結(jié)果集的情況,multipleResults可能是List<List<Object>>集合嵌套集合類型免胃,
// 如果僅僅一個(gè)結(jié)果集的處理結(jié)果音五,直接返回第一個(gè)元素List<Object>結(jié)果即可
return collapseSingleResultList(multipleResults);
}
// 處理結(jié)果集
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) {
// 使用ResultHandler(注意區(qū)分ResultSetHandler)解析好的結(jié)果
// DefaultResultHandler在下文有源碼展示,其實(shí)就是簡(jiǎn)單的使用了一個(gè)List集合保存解析的每一行結(jié)果集結(jié)果
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
// 開始處理結(jié)果集的每一行數(shù)據(jù)(下有源碼細(xì)節(jié))
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 從ResultHandler保存的結(jié)果List中獲取數(shù)據(jù)羔沙,放入multipleResults集合作為參數(shù)返回
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// 關(guān)閉ResultSet結(jié)果集
closeResultSet(rsw.getResultSet());
}
}
// 開始將ResultSet結(jié)果集的每一行處理為對(duì) 象返回
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 判斷當(dāng)前方法的ResultMap是否嵌套了另一個(gè)ResultMap躺涝,比如:
/* <resultMap id="resultMap" type="doman實(shí)體" extends="BaseResultMap">
<collection property="c" resultMap="otherBaseResultMap"/>
</resultMap>
*/
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
// 暫時(shí)不去探究嵌套R(shí)esultMap處理,先來(lái)看單個(gè)ResultMap如何處理的(下有源碼細(xì)節(jié))
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
// 針對(duì)單一ResultMap的情況進(jìn)行結(jié)果集解析
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
ResultHandler<?> resultHandler, RowBounds rowBounds,
ResultMapping parentMapping) throws SQLException {
// ResultContext類可以看做是解析ResultSet過(guò)程的一個(gè)上下文對(duì)象扼雏,用來(lái)記錄當(dāng)前最新解析結(jié)果集行結(jié)果坚嗜,記錄解析行數(shù)夯膀,是否達(dá)到分頁(yè)條目停止解析
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
// 分頁(yè)查詢時(shí),將結(jié)果集偏移量調(diào)整到分頁(yè)開始行
skipRows(rsw.getResultSet(), rowBounds);
// 條件1 : 通過(guò)ResultContext當(dāng)前是否設(shè)置了停止解析 或 到達(dá)分頁(yè)條目 不再進(jìn)一步解析結(jié)果集(下有源碼細(xì)節(jié))
// 條件2 : 結(jié)果集不再有下一行
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
// rowValue表示一個(gè)解析成ResultMap指定類型的一行結(jié)果集數(shù)據(jù)(下有源碼細(xì)節(jié))
Object rowValue = getRowValue(rsw, discriminatedResultMap);
// 將這一行結(jié)果集處理的結(jié)果保存到ResultHandler和ResultContext(下有源碼細(xì)節(jié))
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
// 通過(guò)ResultContext和RowBounds判斷是否需要繼續(xù)解析結(jié)果集ResultSet
private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException {
return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
}
// 存儲(chǔ)解析得到的一行ResultSet結(jié)果
private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext,
Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
if (parentMapping != null) {
linkToParents(rs, parentMapping, rowValue);
} else {
// 存儲(chǔ)結(jié)果(下有源碼細(xì)節(jié))
callResultHandler(resultHandler, resultContext, rowValue);
}
}
// 存儲(chǔ)ResultSet每一行處理結(jié)果
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext,
Object rowValue) {
// ResultContext保存每一次最后解析得到的對(duì)象苍蔬,并記錄解析過(guò)多少行
resultContext.nextResultObject(rowValue);
// 將每一行ResultSet結(jié)果處理結(jié)果存放到ResultHandler的屬性集合中(該類下有DefaultResultHandler實(shí)現(xiàn)源碼細(xì)節(jié))
((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}
// 解析結(jié)果集ResultSet一行數(shù)據(jù)诱建,封裝成目標(biāo)類型返回
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 創(chuàng)建一個(gè)目標(biāo)類型的空對(duì)象(下有源碼細(xì)節(jié))
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
// <rusultMap id="ddd" type="user" autoMapping="true">,可以通過(guò)如上方法碟绑,指定ResultMap采用自動(dòng)映射機(jī)制
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
// 手動(dòng)映射返回結(jié)果屬性俺猿,較為復(fù)雜,需要處理嵌套R(shí)esultMap蜈敢,嵌套子查詢的情況(下有源碼細(xì)節(jié))
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
// 創(chuàng)建ResultMap指定的返回對(duì)象類型
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader,
String columnPrefix) throws SQLException {
this.useConstructorMappings = false;
final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
final List<Object> constructorArgs = new ArrayList<Object>();
// 具體創(chuàng)建返回對(duì)象方法(下有源碼細(xì)節(jié))
/*
ResultMap標(biāo)簽可以指定創(chuàng)建返回類的構(gòu)造器辜荠,如下:
<resultMap id="RoleResultMap" type="RoleDTO">
<constructor>
<arg column="user_id"/>
</constructor>
</resultMap>
*/
Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
// 嵌套查詢?yōu)槿缦虑闆r:
/* <resultMap id="ddd" type="user">
<asoociation property="author" select="selectByUserId">
</resultMap>
*/
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
resultObject = configuration.getProxyFactory().createProxy(resultObject,
lazyLoader, configuration, objectFactory,
constructorArgTypes, constructorArgs);
break;
}
}
}
this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty();
return resultObject;
}
// 根據(jù)ResultMap創(chuàng)建每一行返回的空對(duì)象
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes,
List<Object> constructorArgs, String columnPrefix) throws SQLException {
// 獲取ResultMap的返回類型
final Class<?> resultType = resultMap.getType();
// 解析返回類型的元數(shù)據(jù)信息
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
// 如果是原始類型汽抚,直接使用TypeHandler處理數(shù)據(jù)返回
if (hasTypeHandlerForResultObject(rsw, resultType)) {
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
}
// 如果ResultMap存在構(gòu)造器映射配置抓狭,則通過(guò)構(gòu)造器創(chuàng)建
else if (!constructorMappings.isEmpty()) {
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes,
constructorArgs, columnPrefix);
}
// 如果返回類型是個(gè)接口,或者存在默認(rèn)構(gòu)造器造烁,直接創(chuàng)建一個(gè)空對(duì)象
else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
return objectFactory.create(resultType);
}
// 基于自動(dòng)映射否过,自動(dòng)一依次查找是否于指定構(gòu)造方法匹配,若有自動(dòng)創(chuàng)建對(duì)象
else if (shouldApplyAutomaticMappings(resultMap, false)) {
return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
}
throw new ExecutorException("Do not know how to create an instance of " + resultType);
}
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
// TODO 只要有一個(gè)屬性填充上就表示可以返回該對(duì)象?????????
for (ResultMapping propertyMapping : propertyMappings) {
String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
if (propertyMapping.getNestedResultMapId() != null) {
column = null;
}
if (propertyMapping.isCompositeResult()
|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
|| propertyMapping.getResultSet() != null) {
// 存在嵌套子查詢的處理
Object value =
getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping,
lazyLoader, columnPrefix);
final String property = propertyMapping.getProperty();
if (property == null) {
continue;
} else if (value == DEFERED) {
foundValues = true;
continue;
}
if (value != null) {
foundValues = true;
}
if (value != null
|| (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
metaObject.setValue(property, value);
}
}
}
return foundValues;
}
private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping,
ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
/* <resultMap id="ddd" type="user">
<asoociation property="author" select="selectByUserId">
</resultMap>
*/
if (propertyMapping.getNestedQueryId() != null) {
return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
}
/* <resultMap id="ddd" type="user">
<asoociation property="author" resultSet="ss" select="selectByUserId">
</resultMap>
*/
else if (propertyMapping.getResultSet() != null) {
addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO is that OK?
return DEFERED;
} else {
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
return typeHandler.getResult(rs, column);
}
}
}
補(bǔ)充:使用ResultContext控制解析結(jié)果集數(shù)量例子
ResultHandler
使用一個(gè)list保存解析ResultSet每一行的結(jié)果
public class DefaultResultHandler implements ResultHandler<Object> {
private final List<Object> list;
public DefaultResultHandler() {
list = new ArrayList<Object>();
}
public DefaultResultHandler(ObjectFactory objectFactory) {
list = objectFactory.create(List.class);
}
@Override
public void handleResult(ResultContext<? extends Object> context) {
list.add(context.getResultObject());
}
public List<Object> getResultList() {
return list;
}
}
附錄
MapperMethod與SqlSessionTemplate的關(guān)系
Mybatis集成Spring后惭蟋,通過(guò)向Spring注冊(cè)MapperFactoryBean
生產(chǎn)Mapper接口的代理對(duì)象苗桂,每個(gè)代理對(duì)象都會(huì)持有SqlSessionTemplate
對(duì)象,當(dāng)程序觸發(fā)代理對(duì)象的方法時(shí)告组,JDK動(dòng)態(tài)代理攔截方法調(diào)用煤伟,會(huì)通過(guò)MepperMethod#execute
調(diào)用SqlSessionTemplate
方法,而SqlSessionTemplate
又會(huì)將查詢委托給自己封裝的另一個(gè)代理sqlSessionProxy木缝。
public class MapperProxyFactory<T> {
// ...
// 要生成代理對(duì)的接口
private final Class<T> mapperInterface;
//
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
// 生成Mapper接口的代理對(duì)象
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
public class MapperProxy<T> implements InvocationHandler, Serializable {
// ...
private final SqlSession sqlSession; // 集成Mybatis便锨,該屬性注入SqlSessionTemplate對(duì)象
// 調(diào)用Mapper接口代理對(duì)象方法,會(huì)被該方法攔截
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
}
public class SqlSessionTemplate implements SqlSession, DisposableBean {
private final SqlSessionFactory sqlSessionFactory;
private final ExecutorType executorType;
private final SqlSession sqlSessionProxy;
private final PersistenceExceptionTranslator exceptionTranslator;
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
// 創(chuàng)建代理對(duì)象
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
}
// SqlSessionTemplate內(nèi)部的方法都委托給另一個(gè)代理對(duì)象sqlSessionProxy
public <T> T selectOne(String statement, Object parameter) {
return this.sqlSessionProxy.<T> selectOne(statement, parameter);
}
// ...
}