在 MyBatis 中,TypeHandler
是实现 Java 类型与数据库类型双向转换 的核心组件。无论是处理基础数据类型还是复杂的 JSON、枚举或自定义对象,它都能通过灵活的扩展机制满足开发需求。本文将通过一个 将数据库 JSON 字符串转换为 List<User>
的案例,详解 TypeHandler 的原理与实践。
一、TypeHandler 的作用与原理
1. 核心功能
- 类型转换桥梁:将 Java 对象属性转换为 JDBC 参数(如
PreparedStatement
设置值); - 结果集映射:将数据库查询结果(如
ResultSet
)转换为 Java 对象属性; - 空值处理:统一处理 Java 对象与数据库字段的
NULL
值逻辑。
2. 应用场景
- 内置类型处理:MyBatis 已支持
String
、Integer
、Date
等常见类型的转换; - 复杂类型处理:如 JSON 字符串与对象互转、枚举值与数据库标记映射、CSV 字符串与集合转换等。
二、TypeHandler 的配置与扩展
1. 内置 TypeHandler
MyBatis 默认提供多种 TypeHandler,例如:
StringTypeHandler
:处理VARCHAR
与String
;EnumTypeHandler
:处理枚举与数据库标记(如disabled
转0
);DateTypeHandler
:处理日期类型与TIMESTAMP
的转换。
2. 自定义 TypeHandler 步骤
- 继承
BaseTypeHandler
:实现setNonNullParameter
(Java→JDBC)和getNullableResult
(JDBC→Java)方法; - 注册处理器:
- 全局注册:在
mybatis-config.xml
中通过<typeHandlers>
标签配置; - 局部指定:在 Mapper XML 或注解中通过
typeHandler
属性标记;
- 全局注册:在
- 应用转换逻辑:在实体类字段或 SQL 映射中声明使用自定义 TypeHandler。
三、实战:FastJson 实现 JSON 字符串与 List 转换
1. 场景描述
假设数据库表 user_group
的 users
字段存储 JSON 字符串,需在 Java 中映射为 List<User>
对象:
CREATE TABLE user_group (
id BIGINT PRIMARY KEY,
users VARCHAR(2048) -- 存储格式:[{"id":1,"name":"Alice","age":25},...]
);
2. 实现步骤
① 引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
② 定义 User 实体
public class User {
private Long id;
private String name;
private Integer age;
// getters/setters
}
③ 自定义 TypeHandler
public class ListUserTypeHandler extends BaseTypeHandler<List<User>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
List<User> users, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSON.toJSONString(users)); // Java→JSON字符串
}
@Override
public List<User> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return parseJson(json);
}
private List<User> parseJson(String json) {
return json == null ? null :
JSON.parseObject(json, new TypeReference<List<User>>(){});
}
// 其他重写方法略...
}
④ 全局注册 TypeHandler
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="com.example.ListUserTypeHandler"
javaType="java.util.List" jdbcType="VARCHAR"/>
</typeHandlers>
⑤ 实体类与 Mapper 映射
public class UserGroup {
private Long id;
@TableField(typeHandler = ListUserTypeHandler.class)
private List<User> users;
// getters/setters
}
<!-- UserGroupMapper.xml -->
<select id="selectUserGroup" resultType="UserGroup">
SELECT * FROM user_group WHERE id = #{id}
</select>
四、测试与验证
UserGroup group = sqlSession.selectOne("selectUserGroup", 1L);
System.out.println(group.getUsers());
// 输出:[User{id=1, name='Alice', age=25}, User{id=2, name='Bob', age=30}]
五、总结与扩展
优势
- 解耦业务与持久化逻辑:将类型转换代码集中管理,提升可维护性;
- 支持复杂场景:通过自定义逻辑处理加密数据、多语言字段等特殊需求。
扩展方向
- 泛型支持:抽象通用 JSON TypeHandler,通过
TypeReference
适配不同泛型类; - 性能优化:针对高频转换类型缓存解析结果,减少重复计算。
- 泛型支持:抽象通用 JSON TypeHandler,通过
通过合理使用 TypeHandler,开发者可以显著提升 MyBatis 在处理复杂数据类型时的灵活性与代码整洁度,是高效 ORM 实践的重要工具。