MyBatis 类型处理器 TypeHandler

一、什么是类型处理器?

用于 JavaType 与 JdbcType 之间的转换,用于 PreparedStatement 设置参数值和从 ResultSet 或 CallableStatement 中取出一个值。

MyBatis 内置了大部分基本类型的类型处理器,所以对于基本类型可以直接处理,当我们需要处理其他类型的时候就需要自定义类型处理器。

如:一个 List<String> 类型的 JavaType ,在存储时,需要转换为以逗号分隔的VARCHAR 类型,在查询的时候,又要返回 List<String>

二、MyBatis 内置的 TypeHandler

在 MyBatis 的 TypeHandlerRegistry 类型中,可以看到内置的类型处理器。内置处理器比较多,这里整理常见的一些。

TypeHandler描述
BooleanTypeHandler用于 java 类型 boolean,jdbc 类型 bit、boolean
ByteTypeHandler用于 java 类型 byte,jdbc 类型 TINYINT
ShortTypeHandler用于 java 类型 short,jdbc 类型 SMALLINT
IntegerTypeHandler用于 INTEGER 类型
LongTypeHandler用于 long 类型
FloatTypeHandler用于 FLOAT 类型
DoubleTypeHandler用于 double 类型
StringTypeHandler用于 java 类型 string,jdbc 类型 CHAR、VARCHAR
ArrayTypeHandler用于 jdbc 类型 ARRAY
BigDecimalTypeHandler用于 java 类型 BigDecimal,jdbc 类型 REAL、DECIMAL、NUMERIC
DateTypeHandler用于 java 类型 Date,jdbc 类型 TIMESTAMP
DateOnlyTypeHandler用于 java 类型 Date,jdbc 类型 DATE
TimeOnlyTypeHandler用于 java 类型 Date,jdbc 类型 TIME

注意: 对于常见的 Enum 类型,内置了 EnumTypeHandler 进行 Enum 名称的转换和 EnumOrdinalTypeHandler 进行 Enum 序数的转换。这两个类型处理器没有在 TypeHandlerRegistry 中注册,如果需要使用必须手动配置。

三、自定义 TypeHandler

自定义类型处理器是通过实现 org.apache.ibatis.type.TypeHandler 接口实现的。这个接口定义了类型处理器的基本功能,接口定义如下所示。

public interface TypeHandler<T> {
  // 用于把 java 对象设置到 PreparedStatement 的参数中
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  // 用于从 ResultSet 中根据列名取出数据转换为 java 对象
  T getResult(ResultSet rs, String columnName) throws SQLException;
  // 用于从 ResultSet 中根据索引位置取出数据转换为 java 对象
  T getResult(ResultSet rs, int columnIndex) throws SQLException;
  // 用于从 CallableStatement 中根据存储过程取出数据转换为 java 对象
  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}

实际开发中,我们可以继承 org.apache.ibatis.type.BaseTypeHandler 类型来实现自定义类型处理器。这个类型是抽象类型,实现了 TypeHandler 的方法进行通用流程的封装,做了异常处理,并定义了几个类似的抽象方法,如下所示。继承 BaseTypeHandler 类型可以极大地降低开发难度。
在这里插入图片描述

类型转换器还可以通过注解配置 java 类型和 jdbc 类型:

@MappedTypes:注解配置 java 类型
@MappedJdbcTypes:注解配置 jdbc 类型

把TypeHandler配置到程序中有三种方法:

  1. 在 Mapper.xml 中声明
<resultMap id="BaseResultMap" type="com.lizq.springboot.web.bean.User">
	<result column="phones" jdbcType="VARCHAR" property="phones" typeHandler="com.xxx.handler.ListTypeHandler" />
</resultMap>
  1. 在 mybatis 配置文件中设置
<typeHandlers>
	<typeHandler handler="com.xxx.handler.ListTypeHandler"/>
</typeHandlers>
  1. 在 springboot 的 yml 配置文件中设置类型处理器所在的包名
mybatis:
  type-handlers-package: com.xxx.handler

四、自定义List和VARCHAR相互转换的TypeHandler

实现List到VARCHAR的转换。

比如:User 中有个属性的类型是 List 类型,对应的保存到数据库中的字段为VARCHAR 类型。要通过 TypeHandler 在插入的时候把List类型数据转换为String 类型处理,在查询的时候要把查询得到的字符串转换为 List 类型。

1. 继承BaseTypeHandler实现自定义TypeHandler

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

public class ListTypeHandler extends BaseTypeHandler<List<String>> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, String.join(",", parameter));
    }

    @Override
    public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String s = rs.getString(columnName);
        return s == null ? null : Arrays.asList(s.split(","));
    }

    @Override
    public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String s = rs.getString(columnIndex);
        return s == null ? null : Arrays.asList(s.split(","));
    }

    @Override
    public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String s = cs.getString(columnIndex);
        return s == null ? null : Arrays.asList(s.split(","));
    }
}

2. 对应实体类

import lombok.Data;
import java.util.List;

@Data
public class User {
    private String id;
    private String name;
    private int age;
    private String sex;
    // 电话号码
    private List<String> phones;
}

3. 编写Mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springboot.Mapper.UserMapper">

    <resultMap id="user" type="com.springboot.bean.User">
        <result column="id" jdbcType="VARCHAR" property="id" />
        <result column="name" jdbcType="VARCHAR" property="name" />
        <result column="age" jdbcType="INTEGER" property="age" />
        <result column="sex" jdbcType="VARCHAR" property="sex" />
        <!--配置typeHandler-->
        <result column="phones" jdbcType="VARCHAR" property="phones" typeHandler="com.lizq.springboot.web.typehandler.ListTypeHandler" />
    </resultMap>

    <insert id="insertUser">
        INSERT INTO user(id, name, age, sex, phones
        ) VALUES(#{id}, #{name}, #{age}, #{sex},
                /*配置typeHandler*/
               #{phones, jdbcType=VARCHAR ,typeHandler=com.lizq.springboot.web.typehandler.ListTypeHandler})
    </insert>

    <select id="getUserById" resultMap="user">
        SELECT * FROM user WHERE id = #{id}
    </select>
</mapper>

4. 测试

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值