Mybatis—ParameterHandler
迪丽瓦拉
2024-04-04 16:50:49
0

  使用PreparedStatement或者CallableStatement对执行SQL语句时,如果SQL语句中有参数占位符,那么在之前就需要为参数占位符设置值。ParameterHandler的主要职责就是给参数占位符赋值,在赋值时又结合使用了TypeHandler来对目标参数进行Java和JDBC类型之间的转换。
  ParameterHandler相对于Mybatis其它的组件来讲是相比较简单的,其接口只定义了两个方法:

  1. getParameterObject,用于获取执行Mapper时传入的参数对象;
  2. setParameters,用于为PreparedStatement或者CallableStatement对象设置参数值。
public interface ParameterHandler {Object getParameterObject();void setParameters(PreparedStatement ps) throws SQLException;}

DefaultParameterHandler

  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);}}}}
}

  结合源代码,可以概括为下述几个步骤:

  1. 从BoundSql类中获取当前SQL语句中的占位符参数ParameterMapping定义,如果不为空就直接遍历ParameterMapping定义,为每一个占位符参数赋值;
  2. 如果占位符参数的ParameterMode不是OUT就进行赋值处理;
  3. 如果在类型处理器中找到对应的typeHandler,就直接赋值;
  4. 如果在没有找到对应的typeHandler,将参数转化为MetaObject反射工具类,然后从元数据类中寻找当前参数的值;
  5. 得到value值之后,再获取在ParameterMapping中定义的typeHandler类型处理器和Java类型;
  6. 调用typeHandler类型处理器的setParameter方法,将value值设置到当前的PreparedStatement对象。

相关内容