四大对象-ResultSetHandler(结果集映射)
一、ResultSetHandler
ResultSetHandler在Mybatis四大对象中负责将数据库结果集转换为Java对象集合。它是一个接口,有且只有一个实现类DefaultResultSetHandler。
public interface ResultSetHandler {
< E> List< E> handleResultSets ( Statement stmt) throws SQLException;
< E> Cursor< E> handleCursorResultSets ( Statement stmt) throws SQLException;
void handleOutputParameters ( CallableStatement cs) throws SQLException;
}
handleResultSets是处理数据库结果集最核心的方法。
二、DefaultResultSetHandler
DefaultResultSetHandler是ResultSetHandler结果的唯一实现类,结果集的处理基本是都在ResultSetHandler里面。我们通过ResultSetHandler来看看结果集的处理流程,因为处理过程中的细节非常多,需要考虑各种配置,嵌套之类的,因此我们梳理流程旨在弄清楚整个主流程,不会过于解析每一行代码。
2.1 DefaultResultSetHandler#handleResultSets
handleResultSets方法将ResultSet结果集转换为对应的Java类对象集合,在在StatementHandler里面的query方法会调用该方法。
@Override
public List< Object> handleResultSets ( Statement stmt) throws SQLException {
ErrorContext. instance ( ) . activity ( "handling results" ) . object ( mappedStatement. getId ( ) ) ;
final List< Object> multipleResults = new ArrayList < Object> ( ) ;
int resultSetCount = 0 ;
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) ;
handleResultSet ( rsw, resultMap, multipleResults, null) ;
rsw = getNextResultSet ( stmt) ;
cleanUpAfterHandlingResultSet ( ) ;
resultSetCount++ ;
}
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++ ;
}
}
return collapseSingleResultList ( multipleResults) ;
}
1. mappedStatement. getResultMaps ( ) ;
2. handleResultSet ( rsw, resultMap, multipleResults, null) ;
3. return collapseSingleResultList ( multipleResults) ;
PS:后面重点解析第二步handleResultSet里面的细节。
2.2 DefaultResultSetHandler#handleResultSet
handleResultSet根据规则(resultMap)处理 ResultSet,将结果集转换为Object列表,并保存到multipleResults
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) {
DefaultResultHandler defaultResultHandler = new DefaultResultHandler ( objectFactory) ;
handleRowValues ( rsw, resultMap, defaultResultHandler, rowBounds, null) ;
multipleResults. add ( defaultResultHandler. getResultList ( ) ) ;
} else {
handleRowValues ( rsw, resultMap, resultHandler, rowBounds, null) ;
}
}
} finally {
closeResultSet ( rsw. getResultSet ( ) ) ;
}
}
1. handleRowValues
2. multipleResults. add
PS:这一步主要是做一些逻辑的判断,主要处理是在handleRowValues方法里面
2.3 DefaultResultSetHandler#handleRowValues
public void handleRowValues ( ResultSetWrapper rsw, ResultMap resultMap, ResultHandler< ? > resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if ( resultMap. hasNestedResultMaps ( ) ) {
ensureNoRowBounds ( ) ;
checkResultHandler ( ) ;
handleRowValuesForNestedResultMap ( rsw, resultMap, resultHandler, rowBounds, parentMapping) ;
} else {
handleRowValuesForSimpleResultMap ( rsw, resultMap, resultHandler, rowBounds, parentMapping) ;
}
}
1. handleRowValuesForNestedResultMap
2. handleRowValuesForSimpleResultMap
PS:这一步做一些简单的判断,分两种情况处理
2.4 DefaultResultSetHandler#handleRowValuesForSimpleResultMap
private void handleRowValuesForSimpleResultMap ( ResultSetWrapper rsw, ResultMap resultMap, ResultHandler< ? > resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext< Object> resultContext = new DefaultResultContext < Object> ( ) ;
skipRows ( rsw. getResultSet ( ) , rowBounds) ;
while ( shouldProcessMoreRows ( resultContext, rowBounds) && rsw. getResultSet ( ) . next ( ) ) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap ( rsw. getResultSet ( ) , resultMap, null) ;
Object rowValue = getRowValue ( rsw, discriminatedResultMap) ;
storeObject ( resultHandler, resultContext, rowValue, parentMapping, rsw. getResultSet ( ) ) ;
}
}
1. skipRows
2. shouldProcessMoreRows
3. resolveDiscriminatedResultMap
3. getRowValue
4. storeObject
PS:这一步做了更细节的处理,到了将数据库记录转换为Java对象的部分了。注意这里会循环处理,并且会处理分页的信息。getRowValue是获取记录的核心方法
2.5 DefaultResultSetHandler#getRowValue()
private Object getRowValue ( ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap ( ) ;
Object resultObject = createResultObject ( rsw, resultMap, lazyLoader, null) ;
if ( resultObject != null && ! hasTypeHandlerForResultObject ( rsw, resultMap. getType ( ) ) ) {
final MetaObject metaObject = configuration. newMetaObject ( resultObject) ;
boolean foundValues = ! resultMap. getConstructorResultMappings ( ) . isEmpty ( ) ;
if ( shouldApplyAutomaticMappings ( resultMap, false ) ) {
foundValues = applyAutomaticMappings ( rsw, resultMap, metaObject, null) || foundValues;
}
foundValues = applyPropertyMappings ( rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader. size ( ) > 0 || foundValues;
resultObject = foundValues ? resultObject : null;
return resultObject;
}
return resultObject;
}
1. createResultObject
2. shouldApplyAutomaticMappings- > applyAutomaticMappings
3. applyPropertyMappings
4. 映射失败则会把结果置为null
PS:getRowValue方法是处理一行记录,再前面的handleRowValuesForSimpleResultMap中会循环调用该方法。getRowValue方法内部会处理映射明确和不明确的列,不明确的列只有在开启了自动映射的情况才会处理,如果存在映射失败,就会将结果置为null,避免错误。
2.6 DefaultResultSetHandler#applyAutomaticMappings
我们看一看DefaultResultSetHandler#applyAutomaticMappings中处理未明确映射关系的列是怎么处理的,对于明确关系的列也比较类似。
private boolean applyAutomaticMappings ( ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
List< UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings ( rsw, resultMap, metaObject, columnPrefix) ;
boolean foundValues = false ;
if ( autoMapping. size ( ) > 0 ) {
for ( UnMappedColumnAutoMapping mapping : autoMapping) {
final Object value = mapping. typeHandler. getResult ( rsw. getResultSet ( ) , mapping. column) ;
if ( value != null) {
foundValues = true ;
}
if ( value != null || ( configuration. isCallSettersOnNulls ( ) && ! mapping. primitive) ) {
metaObject. setValue ( mapping. property, value) ;
}
}
}
return foundValues;
}
1. 首先会在一个集合里面讲未明确映射的列保存起来,先将他获取出来。
2. 然后从数据库记录中,根据列的名称获取到列对应的Value
3. 通过反射模块提供的metaObject设值到parameterObject中。注意metaObject是Mybatis反射模块以及封装好的相关类,给属性设值提供简单的使用方式
PS:未明确映射关系的列处理方法就是把属性名当做列名,去数据库记录中获取值,获取到之后通过反射设置到结果对象( 有映射关系那么就是通过映射列名去获取值了) 。
三、辅助类
3.1 ResultSetWrapper
ResultSetWrapper内部包装了ResultSet,提供了一些相关的操作,这些操作会在DefaultResultSetHandler中被使用到。在前面的DefaultResultSetHandler#applyAutomaticMappings中我们看到是通过 ResultSetWrapper变量rsw.getResultSet()来获得指定字段的值。其实ResultSetWrapper可以理解为对原始的结果集进行了包装。在DefaultResultSetHandler#handleResultSets中:
ResultSetWrapper rsw = getFirstResultSet ( stmt) ;
通过Statement获取结果集并封装成ResultSetWrapper对象,ResultSetWrapper对象实际上就包含了一次访问数据库得到的全部结果,并且封装了相关属性,便于ResultSetHandler中进行处理。
3.2 DefaultResultSetHandler#getFirstResultSet
private ResultSetWrapper getFirstResultSet ( Statement stmt) throws SQLException {
ResultSet rs = stmt. getResultSet ( ) ;
while ( rs == null) {
if ( stmt. getMoreResults ( ) ) {
rs = stmt. getResultSet ( ) ;
} else {
if ( stmt. getUpdateCount ( ) == - 1 ) {
break ;
}
}
}
return rs != null ? new ResultSetWrapper ( rs, configuration) : null;
}
1. 获取ResultSet
2. 将ResultSet和Configuration配置对象封装到ResultSetWrapper对象中去,后续ResultSetHandler操作结果集实际上是操作ResultSetWrapper。
四、小结
本文给出了ResultSetHandler处理数据库结果集的大体流程,并未细致的分析每一行代码,有兴趣可以自行研究,在掌握了主要的流程之后,在使用的时候遇到问题我们也能够有思路去应对。 下面是前面代码的一个简单流程图展示:
五、参考