Handler
参数处理
Mybatis对接口实参的解析发生在创建Statement之前,对接口参数解析结果如下:
单个参数 : 直接将调用接口传入的实参返回,不需要进一步解析
多个参数:多个参数的情况下,会将参数转换成【参数名 -> 实参值】的映射关系Map
若接口形参使用了@Param参数,使用@Param参数指定的名称
若接口形参未使用@Param参数,JDK8以上可通过参数-parameters打开形参名称解析,未打开则解析结果为arg0、arg1...形式的【映射关系】
Mybatis还会为每个接口形参根据其位置生成一个兜底的param0、param1...形式的【映射关系】
ParamNameResolver
类的功能是解析Mapper接口入参名称,解析参数的时机为:
public class MapperMethod {
// ...
private final SqlCommand command; // 当前要操作的SQL标签,为在Mapper.xml文件中使用的<select><update><delete><insert>标签
private final MethodSignature method; // 记录mapper接口命名标记信息
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
// ...
case SELECT:
// ...
// 使用ParamNameResolver开始解析方法调用的【形参名->实参值】映射关系
// 当方法仅有一个形参时,param即为方法传入实参
// 当方法有多个形参是,param为Map类型,记录【形参名->实参值】映射关系
Object param = method.convertArgsToSqlCommandParam(args);
// 集成Spring时,当前的SqlSession对象为SqlTemplate类对象
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; // 记录解析得到的入参名称,映射关系为【参数位置 -> 参数名称】
private boolean hasParamAnnotation; // 标记该方法是否使用了@Param注解
// ...
public ParamNameResolver(Configuration config, Method method) {
// 获取接口参数类型数组
final Class<?>[] paramTypes = method.getParameterTypes();
// 获取接口每个参数的注解,由于参数前可以采用多个注解,因此使用二维数组
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
// 记录方法参数个数,使用paramTypes数组长度也一样,如果没有被注解修饰的参数也会作为一个空数组放入这个二维数组
int paramCount = paramAnnotations.length;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
// 若当前参数类型为RowBounds或者ResultHandler不处理
if (isSpecialParameter(paramTypes[paramIndex])) {
continue;
}
String name = null;
// 遍历每一个参数的注解,查询是否使用了@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()) {
// 将入参解析为arg0、arg1格式的名称
// jdk8(含)以上版本,可以在编译类的时候使用 -parameters 命令,那么就可以获取方法参数的名称
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// 直接使用数字0,1,2作为入参名称
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
/**
* 解析接口参数名称
* @param args 调用本接口的实参
* @return 使用Object类型返回,方法仅有一个形参时返回入参对象,有多个形参是,返回【形参名->实参值】映射关系Map对象
**/
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
// 如果调用接口实参为null 或 从接口上解析得到的参数个数为0
if (args == null || paramCount == 0) {
return null;
}
// 如果没有使用@Param注解且参数就一个,直接返回传入的实参即可
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()) {
// 保存参数名称 -> 实参值 映射关系
param.put(entry.getValue(), args[entry.getKey()]);
// 生成一个当前位置参数名称,格式为param1.....
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// 若不存在这个格式的参数名称,额外保存param1 -> 实参值 的映射关系
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
// 最终返回的一定有param1 -> 实参值的映射
// 以下两种映射每个参数必存在一种
// arg0 -> 实参
// @Param注解定义名称 -> 实参
return param;
}
}
}
StatementHandler
JDBC处理器,基于JDBC构建Statement并设置参数,然后执行SQL。每调用会话当中一次SQL,都会有与之相对应的且唯一的Statement实例。
PreparedStatementHandler
相对来说,PreparedStatement的应用场景是所有Statement中应用最多的,这里以其对应的PreparedStatementHandler为例进行学习。
创建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();
// 通过Configuration创建StatementHandler,然后由StatementHandler创建Statement
// 这里以PreparedStatementHandler创建PreparedStatement为例
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds,
resultHandler, boundSql);
// 拥有了PreparedStatementHandler之后,创建PreparedStatement
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
}
// 通过PreparedStatementHandler之后,创建PreparedStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
// 通过BaseStatementHandler创建PreparedStatement
stmt = handler.prepare(connection, transaction.getTimeout());
// 为PreparedStatement的占位符?设置参数
handler.parameterize(stmt);
return stmt;
}
}
// 展示SimpleExecutor类中通过Configuration创建PreparedStatement的相关方法
public class Configuration {
// ...
// 通过Configuration创建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通过RoutingStatementHandler创建不同种类的StatementHandler,主要根据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) {
// 根据MappedStatement的配置信息,选择创建不同的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创建PreparedStatement对象,通过调用父类BaseStatementHandler抽取的共同方法prepare实现
public abstract class BaseStatementHandler implements StatementHandler {
// 创建Statement对象
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// instantiateStatement是个抽象方法,由子类StatementHandler、PreparedStatementHandler、CallableStatementHandler实现
statement = instantiateStatement(connection);
setStatementTimeout(statement, transactionTimeout);
setFetchSize(statement);
return statement;
} catch (SQLException e) {
// ...
} catch (Exception e) {
// ...
}
}
}
public class PreparedStatementHandler extends BaseStatementHandler {
// ...
// 实现父类BaseStatementHandler中的抽象方法instantiateStatement,创建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
通过TypeHandler为PreparedStatement设置参数
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());
// 创建好PreparedStatement之后,为其设置参数
handler.parameterize(stmt);
return stmt;
}
}
public class PreparedStatementHandler extends BaseStatementHandler {
// ...
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
// 设置参数处理器,有且仅有此实现
public class DefaultParameterHandler implements ParameterHandler {
// ...
public void setParameters(PreparedStatement ps) {
// 得到Sql的相关参数信息,内含TypeHandler,JdbcType,JavaType
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
// 不是存储过程的OUT参数
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
}
// Mapper接口没有形参,也就没有实参,直接将要设置的value值赋值为null
else if (parameterObject == null) {
value = null;
}
// 检查是否有TypeHandler可以处理当前接口实参类型,符合这个方法的话表示当前接口方法仅有一个形参且为基本类型,
// 否则parameterObject为Map类型
// TypeHandlerRegistry记录了 JavaType -> JdbcType -> TypeHandler 的映射关系,
// 存在 JavaType -> null -> TypeHandler 的映射关系,表示该java类型没有指定jdbc类型默认使用的TypeHandler
else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
// TODO 这个metaObject对象为什么不直接作为本方法的全局变量????
// TODO 如果parameterObject为Map<String,Object>类型、非简单类型,不是每次都需要重新解析???
// MetaObject可以通过反射获取Map<String,Object>以及用户自定义对象属性的值
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 {
// 通过TypeHandler为PreparedStatement设置占位符实参
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
// ...
}
}
}
}
}
}
ResultSetHandler
执行数据库查询,处理返回的结果集
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());
// 通过PreparedStatementHandler执行数据库查询操作
return handler.query(stmt, resultHandler);
} finally {
// 关闭PreparedStatement
closeStatement(stmt);
}
}
}
// 通过PreparedStatementHandler触发数据库操作
public class PreparedStatementHandler extends BaseStatementHandler {
// ...
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 调用JDBC的PreparedStatement#execute执行数据库操作
ps.execute();
// 使用ResultSetHandler处理返回的结果集ResultSet
return resultSetHandler.handleResultSets(ps);
}
}
// 使用ResultSetHandler处理返回结果集ResultSet
public class DefaultResultSetHandler implements ResultSetHandler {
// ...
public List<Object> handleResultSets(Statement stmt) throws SQLException {
final List<Object> multipleResults = new ArrayList<>();
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++;
}
// ...
// 由于存在存储过程有多个结果集的情况,multipleResults可能是List<List<Object>>集合嵌套集合类型,
// 如果仅仅一个结果集的处理结果,直接返回第一个元素List<Object>结果即可
return collapseSingleResultList(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) {
// 使用ResultHandler(注意区分ResultSetHandler)解析好的结果
// DefaultResultHandler在下文有源码展示,其实就是简单的使用了一个List集合保存解析的每一行结果集结果
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
// 开始处理结果集的每一行数据(下有源码细节)
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 从ResultHandler保存的结果List中获取数据,放入multipleResults集合作为参数返回
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// 关闭ResultSet结果集
closeResultSet(rsw.getResultSet());
}
}
// 开始将ResultSet结果集的每一行处理为对 象返回
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 判断当前方法的ResultMap是否嵌套了另一个ResultMap,比如:
/* <resultMap id="resultMap" type="doman实体" extends="BaseResultMap">
<collection property="c" resultMap="otherBaseResultMap"/>
</resultMap>
*/
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
// 暂时不去探究嵌套ResultMap处理,先来看单个ResultMap如何处理的(下有源码细节)
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
// 针对单一ResultMap的情况进行结果集解析
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
ResultHandler<?> resultHandler, RowBounds rowBounds,
ResultMapping parentMapping) throws SQLException {
// ResultContext类可以看做是解析ResultSet过程的一个上下文对象,用来记录当前最新解析结果集行结果,记录解析行数,是否达到分页条目停止解析
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
// 分页查询时,将结果集偏移量调整到分页开始行
skipRows(rsw.getResultSet(), rowBounds);
// 条件1 : 通过ResultContext当前是否设置了停止解析 或 到达分页条目 不再进一步解析结果集(下有源码细节)
// 条件2 : 结果集不再有下一行
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
// rowValue表示一个解析成ResultMap指定类型的一行结果集数据(下有源码细节)
Object rowValue = getRowValue(rsw, discriminatedResultMap);
// 将这一行结果集处理的结果保存到ResultHandler和ResultContext(下有源码细节)
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
// 通过ResultContext和RowBounds判断是否需要继续解析结果集ResultSet
private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException {
return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
}
// 存储解析得到的一行ResultSet结果
private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext,
Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
if (parentMapping != null) {
linkToParents(rs, parentMapping, rowValue);
} else {
// 存储结果(下有源码细节)
callResultHandler(resultHandler, resultContext, rowValue);
}
}
// 存储ResultSet每一行处理结果
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext,
Object rowValue) {
// ResultContext保存每一次最后解析得到的对象,并记录解析过多少行
resultContext.nextResultObject(rowValue);
// 将每一行ResultSet结果处理结果存放到ResultHandler的属性集合中(该类下有DefaultResultHandler实现源码细节)
((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}
// 解析结果集ResultSet一行数据,封装成目标类型返回
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建一个目标类型的空对象(下有源码细节)
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">,可以通过如上方法,指定ResultMap采用自动映射机制
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
// 手动映射返回结果属性,较为复杂,需要处理嵌套ResultMap,嵌套子查询的情况(下有源码细节)
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
// 创建ResultMap指定的返回对象类型
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>();
// 具体创建返回对象方法(下有源码细节)
/*
ResultMap标签可以指定创建返回类的构造器,如下:
<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) {
// 嵌套查询为如下情况:
/* <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;
}
// 根据ResultMap创建每一行返回的空对象
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes,
List<Object> constructorArgs, String columnPrefix) throws SQLException {
// 获取ResultMap的返回类型
final Class<?> resultType = resultMap.getType();
// 解析返回类型的元数据信息
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
// 如果是原始类型,直接使用TypeHandler处理数据返回
if (hasTypeHandlerForResultObject(rsw, resultType)) {
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
}
// 如果ResultMap存在构造器映射配置,则通过构造器创建
else if (!constructorMappings.isEmpty()) {
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes,
constructorArgs, columnPrefix);
}
// 如果返回类型是个接口,或者存在默认构造器,直接创建一个空对象
else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
return objectFactory.create(resultType);
}
// 基于自动映射,自动一依次查找是否于指定构造方法匹配,若有自动创建对象
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 只要有一个属性填充上就表示可以返回该对象?????????
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);
}
}
}
补充:使用ResultContext控制解析结果集数量例子
ResultHandler
使用一个list保存解析ResultSet每一行的结果
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的关系
Mybatis集成Spring后,通过向Spring注册MapperFactoryBean
生产Mapper接口的代理对象,每个代理对象都会持有SqlSessionTemplate
对象,当程序触发代理对象的方法时,JDK动态代理拦截方法调用,会通过MepperMethod#execute
调用SqlSessionTemplate
方法,而SqlSessionTemplate
又会将查询委托给自己封装的另一个代理sqlSessionProxy。
public class MapperProxyFactory<T> {
// ...
// 要生成代理对的接口
private final Class<T> mapperInterface;
//
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
// 生成Mapper接口的代理对象
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对象
// 调用Mapper接口代理对象方法,会被该方法拦截
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;
// 创建代理对象
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
}
// SqlSessionTemplate内部的方法都委托给另一个代理对象sqlSessionProxy
public <T> T selectOne(String statement, Object parameter) {
return this.sqlSessionProxy.<T> selectOne(statement, parameter);
}
// ...
}