在 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 执行和结果处理。