在 Mybatis中ParameterHandler 负责 将 Java 对象转换为 SQL 语句中 JDBC Statement 对象所需的参数。 你可以将 ParameterHandler 理解为 Java 对象和 JDBC 参数之间的转换器 或 参数绑定器。
ParameterHandler 的核心作用概括:
ParameterHandler 的主要作用是 从传入的 Java 参数对象中提取参数值,并使用合适的 TypeHandler 将这些 Java 值转换为 JDBC 类型的值,然后将转换后的 JDBC 值设置到 JDBC Statement 对象 (通常是 PreparedStatement) 的参数占位符 (?) 位置上。 它封装了参数绑定的复杂性,使得 MyBatis 的其他组件 (例如 StatementHandler) 无需关心具体的参数绑定细节。
ParameterHandler 将 Java 对象转换为 SQL 参数的详细步骤和机制:
-
ParameterHandler的创建:ParameterHandler实例由StatementHandler创建。StatementHandler会根据MappedStatement对象和传入的参数对象,创建ParameterHandler实例 (通常是DefaultParameterHandler实例)。ParameterHandler的创建通常发生在StatementHandler.parameterize()方法内部,在真正设置 SQL 参数之前。
-
ParameterHandler.setParameters()方法:设置 SQL 参数的核心方法ParameterHandler的核心方法是setParameter(PreparedStatement ps)。 这个方法负责 将 Java 参数对象的值设置到PreparedStatement对象的参数占位符 (?) 位置上。- 输入参数:
PreparedStatement ps: JDBCPreparedStatement对象,参数值将被设置到这个PreparedStatement对象上。
-
获取
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 进行类型转换。
-
迭代
ParameterMapping列表并设置参数值:ParameterHandler会 迭代ParameterMapping列表,对于每个ParameterMapping对象,执行以下步骤:- 获取参数属性名 (
propertyName): 从ParameterMapping对象中获取propertyName。 - 根据
propertyName从 Java 参数对象 (parameterObject) 中获取参数值 (Java 值):- 如果
parameterObject是Map或MetaObject(例如封装了 POJO 对象): 使用MetaObject的反射 API (或 Map 的get()方法) 根据propertyName获取参数值。 - 如果
parameterObject是单个值 (例如String,Integer,Date等): 直接将parameterObject作为参数值。 通常在参数只有一个的情况下使用,或者使用@Param注解显式指定参数名。
- 如果
- 获取
TypeHandler(类型处理器):- 从
ParameterMapping对象中获取typeHandler。 如果ParameterMapping中显式指定了typeHandler,则使用指定的TypeHandler。 - 如果没有显式指定
typeHandler,则根据ParameterMapping的javaType和jdbcType,从TypeHandlerRegistry中查找合适的TypeHandler。 MyBatis 会根据 Java 类型和 JDBC 类型自动选择合适的 TypeHandler。 - 如果找不到合适的
TypeHandler,则使用默认的ObjectTypeHandler。
- 从
- 使用
TypeHandler将 Java 参数值转换为 JDBC 类型的值:- 调用
TypeHandler.setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)方法。 ps: JDBCPreparedStatement对象。i: 参数占位符的索引 (从 1 开始)。ParameterHandler会根据ParameterMapping在List中的顺序,依次设置参数占位符的值。parameter: 从 Java 参数对象中获取到的 Java 参数值。jdbcType:ParameterMapping中定义的 JDBC 类型。TypeHandler.setParameter()方法内部会将 Java 参数值转换为 JDBC 类型的值 (例如将 JavaDate对象转换为 JDBCTIMESTAMP类型的日期字符串或时间戳),并通过PreparedStatement.setXXX()方法 (例如PreparedStatement.setString(),PreparedStatement.setInt(),PreparedStatement.setDate()等) 将转换后的 JDBC 值设置到PreparedStatement对象的指定索引位置。
- 调用
- 获取参数属性名 (
-
完成参数设置:
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通过 JDBCPreparedStatement.setXXX()方法将转换后的 JDBC 值设置到PreparedStatement对象的参数占位符位置。ParameterHandler抽象了参数绑定的复杂性,使得 MyBatis 的其他组件可以专注于 SQL 执行和结果处理。
