全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-20 6 分钟 ✍️ juanwangdev

TypeHandler 接口

TypeHandler 是 MyBatis 中负责 Java 类型与 JDBC 类型之间双向转换的核心接口。当数据库字段类型与 Java 类型不一致时,TypeHandler 负责完成自动转换。

TypeHandler 接口定义

Java
package org.apache.ibatis.type;

public interface TypeHandler<T> {

    // 设置 PreparedStatement 参数
    void setParameter(PreparedStatement ps, int i,
                      T parameter, JdbcType jdbcType) throws SQLException;

    // 从 ResultSet 按列名获取结果
    T getResult(ResultSet rs, String columnName) throws SQLException;

    // 从 ResultSet 按列索引获取结果
    T getResult(ResultSet rs, int columnIndex) throws SQLException;

    // 从 CallableStatement 获取存储过程结果
    T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}

四个方法覆盖了两个方向:

方向方法场景
Java -> 数据库setParameterINSERT/UPDATE 时设置参数
数据库 -> JavagetResult(ResultSet, String)SELECT 查询按列名读取
数据库 -> JavagetResult(ResultSet, int)SELECT 查询按列索引读取
数据库 -> JavagetResult(CallableStatement, int)存储过程返回值

BaseTypeHandler 抽象实现

直接实现 TypeHandler 接口需要处理大量 null 判断的样板代码。MyBatis 提供了 BaseTypeHandler 抽象类,封装了 null 值处理逻辑:

Java
public abstract class BaseTypeHandler<T> extends TypeReference<T>
        implements TypeHandler<T> {

    @Override
    public void setParameter(PreparedStatement ps, int i,
                             T parameter, JdbcType jdbcType) {
        if (parameter == null) {
            if (jdbcType == null) {
                throw new TypeException("...");
            }
            ps.setNull(i, jdbcType.TYPE_CODE);
        } else {
            setNonNullParameter(ps, i, parameter, jdbcType);
        }
    }

    @Override
    public T getResult(ResultSet rs, String columnName) {
        T result = rs.getObject(columnName);
        if (result == null && rs.wasNull()) {
            return null;
        }
        return getNullableResult(rs, columnName);
    }
    // 其他 getResult 方法同理...

    // 子类只需实现以下四个非空方法
    public abstract void setNonNullParameter(...) throws SQLException;
    public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
    public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
    public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
}

推荐:自定义 TypeHandler 时继承 BaseTypeHandler,只需关注非空情况下的转换逻辑,减少样板代码。

内置 TypeHandler 概览

MyBatis 在 org.apache.ibatis.type 包下提供了大量内置 TypeHandler:

基本类型处理器

TypeHandlerJava 类型JDBC 类型
IntegerTypeHandlerIntegerINTEGER
LongTypeHandlerLongBIGINT
StringTypeHandlerStringVARCHAR
BooleanTypeHandlerBooleanBOOLEAN
DoubleTypeHandlerDoubleDOUBLE
FloatTypeHandlerFloatFLOAT
ByteTypeHandlerByteTINYINT
ShortTypeHandlerShortSMALLINT
BigDecimalTypeHandlerBigDecimalDECIMAL/NUMERIC

日期时间处理器

TypeHandlerJava 类型JDBC 类型
DateTypeHandlerjava.util.DateTIMESTAMP
SqlDateTypeHandlerjava.sql.DateDATE
SqlTimeTypeHandlerjava.sql.TimeTIME
SqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMP

Java 8 时间 API 处理器

TypeHandlerJava 类型JDBC 类型
InstantTypeHandlerInstantTIMESTAMP
LocalDateTypeHandlerLocalDateDATE
LocalTimeTypeHandlerLocalTimeTIME
LocalDateTimeTypeHandlerLocalDateTimeTIMESTAMP

枚举处理器

TypeHandlerJava 类型存储方式
EnumTypeHandlerEnum枚举名称(字符串)
EnumOrdinalTypeHandlerEnum枚举索引(整数)

其他处理器

TypeHandlerJava 类型JDBC 类型
ByteArrayTypeHandlerbyte[]BLOB/LONGVARBINARY
BlobTypeHandlerBlobBLOB
ClobTypeHandlerClobCLOB
ObjectTypeHandlerObject任意类型

注册 TypeHandler 的两种方式

方式一:mybatis-config.xml 配置注册

XML
<configuration>
    <typeHandlers>
        <!-- 注册单个 TypeHandler -->
        <typeHandler handler="com.example.handler.JsonTypeHandler"/>

        <!-- 包扫描自动注册 -->
        <package name="com.example.handler"/>
    </typeHandlers>
</configuration>

方式二:注解注册(推荐)

在 TypeHandler 类上添加注解:

Java
@MappedTypes({UserConfig.class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class JsonTypeHandler extends BaseTypeHandler<UserConfig> {
    // 实现...
}
注解作用
@MappedTypes指定该 TypeHandler 处理的 Java 类型
@MappedJdbcTypes指定该 TypeHandler 对应的 JDBC 类型

注解方式更加简洁,推荐在大多数场景下使用。XML 配置方式适合集中管理或第三方 TypeHandler 的注册。

TypeHandler 的自动注册机制

MyBatis 在启动时会自动注册 TypeHandler:

  1. 先注册内置 TypeHandler(基本类型、日期、枚举等)
  2. 再注册配置文件中指定的 TypeHandler
  3. 最后通过注解 @MappedTypes@MappedJdbcTypes 注册的 TypeHandler

当存在多个 TypeHandler 可处理同一类型时,后注册的会覆盖前面的,即局部配置优先于全局默认

完整自定义 TypeHandler 示例

Java
package com.example.handler;

import org.apache.ibatis.type.*;
import java.sql.*;

@MappedTypes({com.example.model.Status.class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class StatusTypeHandler extends BaseTypeHandler<com.example.model.Status> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i,
            com.example.model.Status status, JdbcType jdbcType) throws SQLException {
        ps.setString(i, status.getCode());
    }

    @Override
    public com.example.model.Status getNullableResult(
            ResultSet rs, String columnName) throws SQLException {
        return Status.fromCode(rs.getString(columnName));
    }

    @Override
    public com.example.model.Status getNullableResult(
            ResultSet rs, int columnIndex) throws SQLException {
        return Status.fromCode(rs.getString(columnIndex));
    }

    @Override
    public com.example.model.Status getNullableResult(
            CallableStatement cs, int columnIndex) throws SQLException {
        return Status.fromCode(cs.getString(columnIndex));
    }
}

要点总结

  • TypeHandler 接口定义了 4 个核心方法,覆盖参数设置和结果读取两个方向
  • BaseTypeHandler 封装了 null 值处理逻辑,自定义时继承它只需实现非空方法
  • MyBatis 内置了基本类型、日期、枚举、JSON 等数十种 TypeHandler
  • 注册方式有两种:XML 配置注册和注解 @MappedTypes + @MappedJdbcTypes 注册
  • TypeHandler 注册具有优先级,后注册的覆盖先注册的,字段级别优先于全局级别
  • 自定义 TypeHandler 的核心是 setNonNullParameter(写)和 getNullableResult(读)

📝 发现内容有误?点击此处直接编辑

← 上一篇 JSON 类型处理
下一篇 → 枚举字段映射
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库