自定义 TypeHandler:类型与字段互转

Java 类型与 JDBC 类型不会总是一一对应:比如把 List<String> 存成 VARCHAR 里的 JSON,或把数据库整型映射成自定义对象。MyBatis 用 TypeHandler(类型处理器)负责"Java 类型 ↔ JDBC 类型"的双向转换,内置覆盖了基础类型,特殊类型就要自定义。本节讲实现、注册与使用。

TypeHandler 的职责

一次读写由四个方法分工,通常继承 BaseTypeHandler<T> 只覆写需要的几个:

方法时机作用
setNonNullParameter写库把 Java 参数设进 PreparedStatement
getNullableResult(rs, columnName)查库按列名读值并转成 Java 对象
getNullableResult(rs, columnIndex)查库按下标读值(按列顺序取值时用)
getNullableResult(cs, columnIndex)调用存储过程从 CallableStatement 读值

自定义:JSON 字段处理示例

需求:tags 列存 JSON 文本,Java 侧是 List<String>。继承 BaseTypeHandler,用 Jackson 完成序列化与反序列化:

public class JsonListTypeHandler extends BaseTypeHandler<List<String>> {
    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i,
            List<String> parameter, JdbcType jdbcType) throws SQLException {
        try {
            ps.setString(i, MAPPER.writeValueAsString(parameter));
        } catch (JsonProcessingException e) {
            throw new SQLException(e);
        }
    }

    @Override
    public List<String> getNullableResult(ResultSet rs, String columnName)
            throws SQLException {
        String json = rs.getString(columnName);
        if (json == null || json.isEmpty()) return Collections.emptyList();
        try {
            return MAPPER.readValue(json, new TypeReference<List<String>>() {});
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    // 还需实现 getNullableResult(ResultSet, int) 与 CallableStatement 版本,逻辑同上
}

null 值由 BaseTypeHandler 的 setParameter 兜底处理,不必在 setNonNullParameter 里判空;真实代码三个 getNullableResult 都要补全,具体 API 以官方文档为准。

注册与使用

XML 配置里声明类型处理器,也可配置包扫描自动注册(如 type-handlers-package: com.demo.handler):

<typeHandlers>
    <typeHandler handler="com.demo.handler.JsonListTypeHandler"
                 javaType="java.util.List" jdbcType="VARCHAR"/>
</typeHandlers>

使用位置三选一:

  • resultMap:<result column="tags" property="tags" typeHandler="JsonListTypeHandler"/>
  • 写入参数:#{tags, typeHandler=JsonListTypeHandler}
  • 实体字段注解 @TableField(typeHandler = ...)(MyBatis-Plus 写法,以官方文档为准)。

注册后 Java 类型匹配即自动生效;查询映射、写入参数两条路径都能命中。写完建议补单测,覆盖 null、空串、非法 JSON 三个边界。

自定义 TypeHandler 是 MyBatis 的标准扩展点:先登记 javaType/jdbcType,再在 resultMap 或参数里启用。JSON、枚举、加解密字段这类"Java 与库表长不一样"的场景,一套处理器通吃。

笔记加载中…