mybatis自定义typehandler用于解决java与数据库类型不一致问题,推荐继承basetypehandler实现,并支持局部、包扫描、显式三种注册方式,可处理枚举、json等复杂类型转换。

MyBatis 的自定义类型处理器(TypeHandler)用于解决 Java 类型与数据库字段类型不一致的问题,比如把 JSON 字符串映射为对象、把枚举存为字符串或序号、处理 LocalDateTime 与字符串/时间戳的转换等。关键在于实现 TypeHandler 接口,并在配置中注册。
实现 TypeHandler 接口
最常用的方式是继承 BaseTypeHandler<t></t>(推荐),它已帮你处理了 null 值、空值、泛型绑定等逻辑。以将 UserStatus 枚举存为数据库中的字符串为例:
// 自定义枚举类型处理器
public class UserStatusTypeHandler extends BaseTypeHandler<userstatus> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter.name()); // 写入时:枚举名存入数据库
}
@Override
public UserStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
String value = rs.getString(columnName);
return value == null ? null : UserStatus.valueOf(value); // 读取时:字符串转枚举
}
@Override
public UserStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String value = rs.getString(columnIndex);
return value == null ? null : UserStatus.valueOf(value);
}
@Override
public UserStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String value = cs.getString(columnIndex);
return value == null ? null : UserStatus.valueOf(value);
}
}</userstatus>
注册类型处理器
有三种方式注册,按优先级从高到低:
-
局部注册(推荐):在
<resultmap></resultmap>或<parametermap></parametermap>中通过typeHandler属性指定,只对当前字段生效
<resultmap id="userMap" type="User"><id property="id" column="id"></id><result property="status" column="status" typehandler="com.example.UserStatusTypeHandler"></result></resultmap>
-
包扫描注册:在 MyBatis 配置文件中配置
<typehandlers></typehandlers>,自动扫描指定包下所有 TypeHandler 实现类
<typehandlers><package name="com.example.handler"></package></typehandlers>
- 显式注册单个类:适合少量 Handler,明确控制映射关系
<typehandlers><typehandler handler="com.example.UserStatusTypeHandler" javatype="com.example.UserStatus"></typehandler></typehandlers>
处理复杂类型(如 JSON)
若字段是 JSON 字符串,需转为 Java 对象(如 Map 或自定义 DTO),可借助 Jackson 或 FastJSON:
- 读取时:用
ObjectMapper#readValue(String, Class)将 JSON 字符串反序列化 - 写入时:用
ObjectMapper#writeValueAsString(Object)序列化为字符串 - 注意捕获
JsonProcessingException并包装为RuntimeException,MyBatis 会统一处理
示例节选:
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Map<string object> parameter, JdbcType jdbcType)
throws SQLException {
try {
ps.setString(i, objectMapper.writeValueAsString(parameter));
} catch (JsonProcessingException e) {
throw new RuntimeException("Failed to serialize map to JSON", e);
}
}
@Override
public Map<string object> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
if (json == null) return null;
try {
return objectMapper.readValue(json, new TypeReference<map object>>(){});
} catch (JsonProcessingException e) {
throw new RuntimeException("Failed to deserialize JSON to Map", e);
}
}</map></string></string>
注意事项和技巧
- 确保数据库字段类型支持存储目标内容(如 JSON 字段建议用
TEXT或JSON类型) - 若使用注解方式(
@Select等),可在@Results中通过@Result(typeHandler = ...)指定 - MyBatis 默认已提供常用类型处理器(如
LocalDateTimeTypeHandler),可直接引用或继承扩展 - 避免在 TypeHandler 中做耗时操作(如远程调用、文件读写),它会在每次参数设置或结果映射时执行
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











