MyBatis类型处理器TypeHandler的作用及说明
作者:冰糖心书房
TypeHandler 是 MyBatis 中用于处理 Java 类型与 JDBC 类型之间转换的接口。它在 MyBatis 的参数绑定和结果映射过程中起着至关重要的作用。
为什么需要 TypeHandler?
Java 和 数据库(JDBC)使用不同的类型系统。例如:
- Java 中有
String、Integer、Date、Boolean、enum等类型。 - JDBC 中有
VARCHAR、INTEGER、DATE、BOOLEAN、TIMESTAMP、BLOB等类型。
当 MyBatis 执行 SQL 语句时,需要将 Java 对象中的数据设置到 JDBC 的 PreparedStatement 中(参数绑定),以及将 JDBC 的 ResultSet 中的数据转换为 Java 对象(结果映射)。TypeHandler 就负责处理这两种情况下的类型转换。
TypeHandler 的作用
参数绑定 (Java 类型 -> JDBC 类型):
- 当 MyBatis 将 Java 对象中的数据设置到
PreparedStatement的占位符(#{})时,TypeHandler会将 Java 类型转换为对应的 JDBC 类型。 - 例如,将 Java 的
String类型转换为 JDBC 的VARCHAR类型,将 Java 的Date类型转换为 JDBC 的TIMESTAMP类型。
结果映射 (JDBC 类型 -> Java 类型):
- 当 MyBatis 从
ResultSet中读取数据并将其映射为 Java 对象时,TypeHandler会将 JDBC 类型转换为对应的 Java 类型。 - 例如,将 JDBC 的
VARCHAR类型转换为 Java 的String类型,将 JDBC 的INTEGER类型转换为 Java 的Integer类型。
TypeHandler 的接口定义
public interface TypeHandler<T> {
// 参数绑定:将 Java 类型转换为 JDBC 类型,并设置到 PreparedStatement 中
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
// 结果映射:从 ResultSet 中获取指定列的数据,并将其转换为 Java 类型
T getResult(ResultSet rs, String columnName) throws SQLException;
// 结果映射:从 ResultSet 中获取指定列索引的数据,并将其转换为 Java 类型
T getResult(ResultSet rs, int columnIndex) throws SQLException;
// 结果映射:从 CallableStatement 中获取指定列索引的数据,将其转换为java类型
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}setParameter(): 将 Java 类型的参数parameter设置到PreparedStatement的第i个占位符,并指定 JDBC 类型jdbcType(jdbcType可以为空,MyBatis 会尝试自动推断)。getResult(): 有三个重载方法,分别根据列名、列索引从ResultSet中获取数据,或从CallableStatement获取数据,并将其转换为 Java 类型。
MyBatis 内置的 TypeHandler
MyBatis 内置了许多常用的 TypeHandler,用于处理常见的类型转换。例如:
StringTypeHandler: 处理String类型。IntegerTypeHandler: 处理Integer类型。LongTypeHandler: 处理Long类型。DateTypeHandler: 处理java.util.Date类型。BooleanTypeHandler: 处理Boolean类型。EnumTypeHandler: 处理枚举类型(默认使用枚举的名称)。EnumOrdinalTypeHandler: 处理枚举类型(使用枚举的序数)。BlobTypeHandler: 处理二进制大对象 (BLOB)。ClobTypeHandler: 处理字符大对象 (CLOB)。SqlDateTypeHandler:处理java.sql.Date类型SqlTimeTypeHandler:处理java.sql.Time类型SqlTimestampTypeHandler:处理java.sql.Timestamp类型- …
自定义 TypeHandler
当 MyBatis 内置的 TypeHandler 不能满足需求时,我们可以自定义 TypeHandler。例如:
- 处理特殊类型: 例如,将数据库中的 JSON 字符串转换为 Java 对象,或者将 Java 对象转换为 JSON 字符串存储到数据库中。
- 自定义类型转换逻辑: 例如,对日期类型进行特殊的格式化,或者对枚举类型使用自定义的转换规则。
自定义 TypeHandler 的步骤
1.实现 TypeHandler 接口: 创建一个类,实现 TypeHandler 接口,并实现接口中的方法。
2.注册 TypeHandler: 有两种方式注册自定义的 TypeHandler:
- XML 配置: 在
mybatis-config.xml文件中,使用<typeHandlers>标签注册TypeHandler。
<typeHandlers> <typeHandler handler="com.example.MyTypeHandler" javaType="com.example.MyType" jdbcType="VARCHAR"/> </typeHandlers>
- 或者使用包扫描:
<typeHandlers>
<package name="com.example.typehandler"/>
</typeHandlers>- 注解配置: 在自定义的
TypeHandler类上使用@MappedTypes和@MappedJdbcTypes注解。
@MappedTypes(MyType.class) // 指定 Java 类型
@MappedJdbcTypes(JdbcType.VARCHAR) // 指定 JDBC 类型
public class MyTypeHandler implements TypeHandler<MyType> {
// ... 实现 TypeHandler 接口的方法 ...
}3.指定jdbcType(可选): 如果MyBatis无法推断,则必须通过jdbcType属性为null值指定数据库列的类型
- 示例:
- 自定义一个将数据库中的 VARCHAR 类型转换为 Java 中的枚举类型的 TypeHandler:
// 假设有一个枚举类型
public enum Status {
ACTIVE, INACTIVE, PENDING
}
// 自定义 TypeHandler
@MappedTypes(Status.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class StatusTypeHandler implements TypeHandler<Status> {
@Override
public void setParameter(PreparedStatement ps, int i, Status parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
ps.setString(i, null);
} else {
ps.setString(i, parameter.name()); // 将枚举的名称存储到数据库
}
}
@Override
public Status getResult(ResultSet rs, String columnName) throws SQLException {
String value = rs.getString(columnName);
return getStatus(value);
}
@Override
public Status getResult(ResultSet rs, int columnIndex) throws SQLException {
String value = rs.getString(columnIndex);
return getStatus(value);
}
@Override
public Status getResult(CallableStatement cs, int columnIndex) throws SQLException {
String value = cs.getString(columnIndex);
return getStatus(value);
}
private Status getStatus(String value){
if (value == null) {
return null;
}
try {
return Status.valueOf(value); // 根据名称从数据库中获取枚举值
} catch (IllegalArgumentException e) {
return null; // 或者抛出异常
}
}
}
// 在 mybatis-config.xml 中注册 TypeHandler
<typeHandlers>
<typeHandler handler="com.example.StatusTypeHandler"/>
</typeHandlers>
// 或者在 Mapper XML 文件中使用
<resultMap id="userResultMap" type="User">
<result property="status" column="status" javaType="com.example.Status" jdbcType="VARCHAR" typeHandler="com.example.StatusTypeHandler"/>
</resultMap>
总结
TypeHandler 是 MyBatis 中用于处理 Java 类型与 JDBC 类型之间转换的关键组件。
MyBatis 内置了许多常用的 TypeHandler,在大多数情况下,我们可以直接使用内置的 TypeHandler。
当需要处理特殊类型或自定义类型转换逻辑时,我们可以自定义 TypeHandler,并通过 XML 配置或注解的方式注册自定义的 TypeHandler。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
