在 MyBatis 中,TypeHandler 是一个非常关键的接口,它的作用是在 Java 类型和 JDBC 类型之间进行转换,用来处理 Java 对象与数据库字段之间的映射关系,特别是在类型不一致或需要特殊转换逻辑时。

一、TypeHandler 的作用:

MyBatis 默认已经提供了一些常见类型的 TypeHandler,比如 StringTypeHandlerIntegerTypeHandler 等。但在以下场景下我们通常需要自定义:

  • Java 与数据库字段类型不一致,比如数据库是 VARCHAR,Java 中是 enum
  • 需要将一个对象序列化成 JSON 存入数据库,或反过来;
  • 存取布尔值、日期等,需要特定格式处理。

二、TypeHandler 接口方法说明:

接口:org.apache.ibatis.type.TypeHandler<T>

常用方法包括:

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

// 获取结果(通过列名)
T getResult(ResultSet rs, String columnName);

// 获取结果(通过列索引)
T getResult(ResultSet rs, int columnIndex);

// 获取结果(用于存储过程)
T getResult(CallableStatement cs, int columnIndex);

三、如何自定义 TypeHandler

示例:将 Enum 类型映射为数据库中的整数

假设我们有一个性别枚举:

public enum Gender {
    MALE(1),
    FEMALE(2);

    private final int code;

    Gender(int code) { this.code = code; }

    public int getCode() { return code; }

    public static Gender fromCode(int code) {
        for (Gender g : values()) {
            if (g.code == code) return g;
        }
        throw new IllegalArgumentException("Invalid code: " + code);
    }
}

自定义 TypeHandler:

@MappedTypes(Gender.class)
@MappedJdbcTypes(JdbcType.INTEGER)
public class GenderTypeHandler implements TypeHandler<Gender> {

    @Override
    public void setParameter(PreparedStatement ps, int i, Gender gender, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, gender.getCode());
    }

    @Override
    public Gender getResult(ResultSet rs, String columnName) throws SQLException {
        int code = rs.getInt(columnName);
        return Gender.fromCode(code);
    }

    @Override
    public Gender getResult(ResultSet rs, int columnIndex) throws SQLException {
        int code = rs.getInt(columnIndex);
        return Gender.fromCode(code);
    }

    @Override
    public Gender getResult(CallableStatement cs, int columnIndex) throws SQLException {
        int code = cs.getInt(columnIndex);
        return Gender.fromCode(code);
    }
}

四、注册方式

  1. 在 MyBatis 配置文件中手动注册:
<typeHandlers>
    <typeHandler handler="com.example.handler.GenderTypeHandler"/>
</typeHandlers>
  1. 或使用注解自动扫描(推荐):

在 MyBatis 配置中配置包扫描:

<typeHandlers>
    <package name="com.example.handler"/>
</typeHandlers>
  1. 或在 Mapper 参数上使用注解:
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
    @Result(property = "gender", column = "gender", typeHandler = GenderTypeHandler.class)
})
User getUserById(@Param("id") int id);

五、常见用法扩展:

  • Java Enum ↔ INT、String
  • JSON 字符串 ↔ Java 对象(可结合 Jackson)
  • 日期时间格式定制化处理
  • 布尔值 ↔ “Y”/”N”