MyBatis ParameterHandler 是如何将 Java 对象转换为 SQL 语句中的参数的?

发布于:2025-03-23 ⋅ 阅读:(22) ⋅ 点赞:(0)

在 Mybatis中ParameterHandler 负责 将 Java 对象转换为 SQL 语句中 JDBC Statement 对象所需的参数。 你可以将 ParameterHandler 理解为 Java 对象和 JDBC 参数之间的转换器参数绑定器

ParameterHandler 的核心作用概括:

ParameterHandler 的主要作用是 从传入的 Java 参数对象中提取参数值,并使用合适的 TypeHandler 将这些 Java 值转换为 JDBC 类型的值,然后将转换后的 JDBC 值设置到 JDBC Statement 对象 (通常是 PreparedStatement) 的参数占位符 (?) 位置上。 它封装了参数绑定的复杂性,使得 MyBatis 的其他组件 (例如 StatementHandler) 无需关心具体的参数绑定细节。

ParameterHandler 将 Java 对象转换为 SQL 参数的详细步骤和机制:

  1. ParameterHandler 的创建:

    • ParameterHandler 实例由 StatementHandler 创建。 StatementHandler 会根据 MappedStatement 对象和传入的参数对象,创建 ParameterHandler 实例 (通常是 DefaultParameterHandler 实例)。
    • ParameterHandler 的创建通常发生在 StatementHandler.parameterize() 方法内部,在真正设置 SQL 参数之前。
  2. ParameterHandler.setParameters() 方法:设置 SQL 参数的核心方法

    • ParameterHandler 的核心方法是 setParameter(PreparedStatement ps)。 这个方法负责 将 Java 参数对象的值设置到 PreparedStatement 对象的参数占位符 (?) 位置上。
    • 输入参数:
      • PreparedStatement ps: JDBC PreparedStatement 对象,参数值将被设置到这个 PreparedStatement 对象上。
  3. 获取 BoundSql 对象和 ParameterMapping 列表:

    • ParameterHandler 会从 StatementHandler 传递过来的 BoundSql 对象中 获取 ParameterMapping 列表 (List<ParameterMapping>)ParameterMapping 列表是在解析 Mapper XML 文件时,由 XMLMapperBuilder 解析 SQL 语句中的 #{} 占位符后生成的。
    • ParameterMapping 对象包含了参数的映射信息,例如:
      • propertyName: 参数属性名 (Java 对象中的属性名,#{propertyName} 中的 propertyName)。
      • jdbcType: JDBC 类型 (例如 VARCHAR, INTEGER, DATE 等)。 可以显式指定,也可以由 MyBatis 自动推断。
      • mode: 参数模式 (IN, OUT, INOUT,通常为 IN)。
      • javaType: Java 类型 (例如 String.class, Integer.class, Date.class)。
      • typeHandler: 类型处理器 (TypeHandler)。 如果指定了自定义的 TypeHandler,则使用自定义的 TypeHandler 进行类型转换。
  4. 迭代 ParameterMapping 列表并设置参数值:

    • ParameterHandler迭代 ParameterMapping 列表,对于每个 ParameterMapping 对象,执行以下步骤:
      • 获取参数属性名 (propertyName):ParameterMapping 对象中获取 propertyName
      • 根据 propertyName 从 Java 参数对象 (parameterObject) 中获取参数值 (Java 值):
        • 如果 parameterObjectMapMetaObject (例如封装了 POJO 对象): 使用 MetaObject 的反射 API (或 Map 的 get() 方法) 根据 propertyName 获取参数值。
        • 如果 parameterObject 是单个值 (例如 String, Integer, Date 等): 直接将 parameterObject 作为参数值。 通常在参数只有一个的情况下使用,或者使用 @Param 注解显式指定参数名。
      • 获取 TypeHandler (类型处理器):
        • ParameterMapping 对象中获取 typeHandler 如果 ParameterMapping 中显式指定了 typeHandler,则使用指定的 TypeHandler
        • 如果没有显式指定 typeHandler,则根据 ParameterMappingjavaTypejdbcType,从 TypeHandlerRegistry 中查找合适的 TypeHandler MyBatis 会根据 Java 类型和 JDBC 类型自动选择合适的 TypeHandler。
        • 如果找不到合适的 TypeHandler,则使用默认的 ObjectTypeHandler
      • 使用 TypeHandler 将 Java 参数值转换为 JDBC 类型的值:
        • 调用 TypeHandler.setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) 方法。
        • ps: JDBC PreparedStatement 对象。
        • i: 参数占位符的索引 (从 1 开始)。 ParameterHandler 会根据 ParameterMappingList 中的顺序,依次设置参数占位符的值。
        • parameter: 从 Java 参数对象中获取到的 Java 参数值。
        • jdbcType: ParameterMapping 中定义的 JDBC 类型。
        • TypeHandler.setParameter() 方法内部会将 Java 参数值转换为 JDBC 类型的值 (例如将 Java Date 对象转换为 JDBC TIMESTAMP 类型的日期字符串或时间戳),并通过 PreparedStatement.setXXX() 方法 (例如 PreparedStatement.setString(), PreparedStatement.setInt(), PreparedStatement.setDate() 等) 将转换后的 JDBC 值设置到 PreparedStatement 对象的指定索引位置。
  5. 完成参数设置:

    • ParameterHandler.setParameter() 方法迭代完所有 ParameterMapping 对象后,就完成了所有参数占位符的设置。 PreparedStatement 对象现在包含了完整的 SQL 语句和参数值,可以被 StatementHandler 执行。

ParameterHandler 接口的主要方法:

  • ParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) (构造器): 创建 ParameterHandler 实例。
  • Object getParameterObject();: 获取参数对象。
  • void setParameters(PreparedStatement ps) throws SQLException;: 设置 PreparedStatement 对象的参数。

ParameterHandler 的实现类:

MyBatis 默认只提供了一个 ParameterHandler 接口的实现类:

  • DefaultParameterHandler: ParameterHandler 接口的默认实现类。 负责处理大多数场景下的参数绑定。

关键组件和类:

  • ParameterHandler 接口: 定义了参数处理器的接口。
  • DefaultParameterHandler: ParameterHandler 接口的默认实现类。
  • ParameterMapping 类: 封装了参数的映射信息 (属性名, JDBC 类型, TypeHandler 等)。
  • BoundSql 类: 封装了最终的可执行 SQL 语句和 ParameterMapping 列表。
  • TypeHandler 接口及其实现类: 负责 Java 类型和 JDBC 类型之间的转换。
  • PreparedStatement 接口 (JDBC API): JDBC 预编译 Statement 对象,参数值会被设置到 PreparedStatement 对象上。

总结 ParameterHandler 的作用和参数转换机制:

  • ParameterHandler 负责将 Java 对象转换为 SQL 语句中的参数,实现 Java 类型到 JDBC 类型的映射。
  • ParameterHandler 通过 ParameterMapping 列表获取参数映射信息,并从 Java 参数对象中提取参数值。
  • ParameterHandler 使用 TypeHandler 将 Java 参数值转换为 JDBC 类型的值。
  • ParameterHandler 通过 JDBC PreparedStatement.setXXX() 方法将转换后的 JDBC 值设置到 PreparedStatement 对象的参数占位符位置。
  • ParameterHandler 抽象了参数绑定的复杂性,使得 MyBatis 的其他组件可以专注于 SQL 执行和结果处理。