ParameterHandler 介绍
ParameterHandler
相比于其他的组件就简单很多了,ParameterHandler 译为参数处理器,负责为 PreparedStatement 的 sql 语句参数动态赋值,这个接口很简单只有两个方法
ParameterHandler 只有一个实现类 DefaultParameterHandler
, 它实现了这两个方法。
- getParameterObject:用于读取参数
- setParameters: 用于对 PreparedStatement 的参数赋值
ParameterHandler 的解析过程
上面我们讨论过了 ParameterHandler
的创建过程,下面我们继续上面 parameterSize
流程
这就是具体参数的解析过程了,下面我们来描述一下
public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); // parameterMappings 就是对 #{} 或者 ${} 里面参数的封装 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { // 如果是参数化的SQL,便需要循环取出并设置参数的值 for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); // 如果参数类型不是 OUT ,这个类型与 CallableStatementHandler 有关 // 因为存储过程不存在输出参数,所以参数不是输出参数的时候,就需要设置。 if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; // 得到 #{} 中的属性名 String propertyName = parameterMapping.getProperty(); // 如果 propertyName 是 Map 中的key if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params // 通过key 来得到 additionalParameter 中的value值 value = boundSql.getAdditionalParameter(propertyName); } // 如果不是 additionalParameters 中的key,而且传入参数是 null, 则value 就是null else if (parameterObject == null) { value = null; } // 如果 typeHandlerRegistry 中已经注册了这个参数的 Class 对象,即它是 Primitive 或者是String 的话 else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { // 否则就是 Map MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } // 在通过 SqlSource 的parse 方法得到parameterMappings 的具体实现中,我们会得到parameterMappings 的 typeHandler TypeHandler typeHandler = parameterMapping.getTypeHandler(); // 获取 typeHandler 的jdbc type JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
下面用一个流程图表示一下 ParameterHandler 的解析过程,以简单执行器为例
我们在完成 ParameterHandler 对 SQL 参数的预处理后,回到 SimpleExecutor 中的 doQuery
方法
上面又引出来了一个重要的组件那就是 ResultSetHandler,下面我们来认识一下这个组件
ResultSetHandler
ResultSetHandler 简介
ResultSetHandler 也是一个非常简单的接口
ResultSetHandler 是一个接口,它只有一个默认的实现类,像是 ParameterHandler 一样,它的默认实现类是DefaultResultSetHandler
ResultSetHandler 解析过程
MyBatis 只有一个默认的实现类就是 DefaultResultSetHandler
,DefaultResultSetHandler 主要负责处理两件事
- 处理 Statement 执行后产生的结果集,生成结果列表
- 处理存储过程执行后的输出参数
按照 Mapper 文件中配置的 ResultType 或 ResultMap 来封装成对应的对象,最后将封装的对象返回即可。
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);
// 如果ResultSet 包装器不是null, 并且 resultmap 的数量 > resultSet 的数量的话
// 因为 resultSetCount 第一次肯定是0,所以直接判断 ResultSetWrapper 是否为 0 即可
while (rsw != null && resultMapCount > resultSetCount) {
// 从 resultMap 中取出 resultSet 数量
ResultMap resultMap = resultMaps.get(resultSetCount);
// 处理结果集, 关闭结果集
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
// 从 mappedStatement 取出结果集
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);
}
其中涉及的主要对象有:
ResultSetWrapper
: 结果集的包装器,主要针对结果集进行的一层包装,它的主要属性有
ResultSet
: Java JDBC ResultSet 接口表示数据库查询的结果。有关查询的文本显示了如何将查询结果作为java.sql.ResultSet 返回。然后迭代此ResultSet以检查结果。TypeHandlerRegistry
: 类型注册器,TypeHandlerRegistry 在初始化的时候会把所有的 Java类型和类型转换器进行注册。ColumnNames
: 字段的名称,也就是查询操作需要返回的字段名称ClassNames
: 字段的类型名称,也就是 ColumnNames 每个字段名称的类型JdbcTypes
: JDBC 的类型,也就是 java.sql.Types 类型ResultMap
: 负责处理更复杂的映射关系
在 DefaultResultSetHandler 中处理完结果映射,并把上述结构返回给调用的客户端,从而执行完成一条完整的SQL语句。
</div>