使用PreparedStatement或者CallableStatement对执行SQL语句时,如果SQL语句中有参数占位符,那么在之前就需要为参数占位符设置值。ParameterHandler的主要职责就是给参数占位符赋值,在赋值时又结合使用了TypeHandler来对目标参数进行Java和JDBC类型之间的转换。
ParameterHandler相对于Mybatis其它的组件来讲是相比较简单的,其接口只定义了两个方法:
public interface ParameterHandler {Object getParameterObject();void setParameters(PreparedStatement ps) throws SQLException;}
Mybatis为ParameterHandler提供了一个默认实现类-DefaultParameterHandler,其实现了getParameterObject方法和setParameters方法。getParameterObject方法的实现逻辑相当简单,就是将构造方法传入的parameterObject原样返回。
setParameters方法的实现逻辑相比之下就要复杂很多,DefaultParameterHandler首先获取Mapper配置中的参数映射ParameterMapping;然后遍历所有ParameterMapping,根据其参数名称获取对应的值,最后调用当前参数对应的TypeHandler来为占位符赋值。
@Override
public void setParameters(PreparedStatement ps) {ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());// 获取SQL中的占位符参数定义List parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null) {for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {// 如果类型处理器中有对应的typeHandler,直接赋值value = parameterObject;} else {// 如果没有对应的typeHandler,将参数转化为MetaObject反射工具类// 然后从元数据类中寻找当前参数的值MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}// 获取typeHandler类型处理器TypeHandler typeHandler = parameterMapping.getTypeHandler();// 获取JdbcType Java类型定义JdbcType jdbcType = parameterMapping.getJdbcType();if (value == null && jdbcType == null) {jdbcType = configuration.getJdbcTypeForNull();}try {// 调用typeHandler的setParameter方法完成占位符参数的赋值typeHandler.setParameter(ps, i + 1, value, jdbcType);} catch (TypeException | SQLException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);}}}}
}
结合源代码,可以概括为下述几个步骤: