mybatis自定义类型处理器

Posted justry_deng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis自定义类型处理器相关的知识,希望对你有一定的参考价值。

mybatis自定义类型处理器


相关说明

本文以java枚举GenderEnum与数据库表列类型char相互转换为例进行示例说明。

  • 现有Employee类

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class Employee {
        
        /** 名字 */
        private String name;
        
        /** 年龄 */
        private Integer age;
        
        /** 性别 */
        private GenderEnum gender;
        
        /** 座右铭 */
        private String motto;
        
    }
    
  • Employee类对应的表结构为

编写类型处理器

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 自定义类型装换器:<br/>
 * <ul>
 *     <li>方式一:继承{@link BaseTypeHandler}</li>
 *     <li>方式二:实现{@link TypeHandler}</li>
 * </ul>
 *
 * <br><br>
 * <p>
 * 哪些类型可以相互转换,可通过@@link MappedTypes}和{@link MappedJdbcTypes}进行指定:<br/>
 * <ul>
 *     <li>{@link MappedTypes}指定java类型</li>
 *     <li>{@link MappedJdbcTypes}指定jdbc类型</li>
 * </ul>
 *
 * @author JustryDeng
 * @since 2021/9/12 15:49:44
 */
@MappedTypes(value = {GenderEnum.class})
@MappedJdbcTypes(value = {JdbcType.CHAR})
public class GenderEnumHandler extends BaseTypeHandler<GenderEnum> {
    
    /**
     * 入库时调用
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, GenderEnum parameter, JdbcType jdbcType) throws SQLException {
        // 具体调用ps的什么setXxx方法,要看你的数据类型
        ps.setInt(i, parameter.getGender());
    }
    
    /**
     * 出库时调用
     */
    @Override
    public GenderEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        // 具体调用rs的什么getXxx方法,要看你的数据类型
        int i = rs.getInt(columnName);
        if (i == 0) {
            return GenderEnum.WOMAN;
        }
        if (i == 1) {
            return GenderEnum.MAN;
        }
        throw new IllegalArgumentException("GenderEnum un-support gender " + i);
    }
    
    /**
     * 出库时调用
     */
    @Override
    public GenderEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        // 具体调用rs的什么getXxx方法,要看你的数据类型
        int i = rs.getInt(columnIndex);
        if (i == 0) {
            return GenderEnum.WOMAN;
        }
        if (i == 1) {
            return GenderEnum.MAN;
        }
        throw new IllegalArgumentException("GenderEnum un-support gender " + i);
    }
    
    /**
     * 出库时调用
     */
    @Override
    public GenderEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        // 具体调用rs的什么getXxx方法,要看你的数据类型
        int i = cs.getInt(columnIndex);
        if (i == 0) {
            return GenderEnum.WOMAN;
        }
        if (i == 1) {
            return GenderEnum.MAN;
        }
        throw new IllegalArgumentException("GenderEnum un-support gender " + i);
    }
}

启用类型处理器

方式一:直接用mybatis总配置类注册处理器

import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * mybatis类型处理器配置
 *
 * @author JustryDeng
 * @since 2021/9/12 16:34:45
 */
@Component
public class MybatisTypeHandlerConfig {
    
    final List<SqlSessionFactory> sqlSessionFactoryList;
    
    public MybatisTypeHandlerConfig(@Autowired List<SqlSessionFactory> sqlSessionFactoryList) {
        this.sqlSessionFactoryList = sqlSessionFactoryList;
    }
    
    @PostConstruct
    public void initHandler () {
        if (sqlSessionFactoryList == null) {
            return;
        }
        sqlSessionFactoryList.forEach(sqlSessionFactory -> {
            sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().register(GenderEnumHandler.class);
        });
    }
}

方式二:通过配置文件指定处理器所处的包

# springboot项目,可通过指定处理器所在包(或祖先包)来启动处理器
mybatis.type-handlers-package=com.example.mybatis.handler

注:如果项目用了mybatis-plus,那么mybatis.type-handlers-package可能会失效,此时可以通过mybatis-plus.type-handlers-package来指定。

方式三:在编写SQL时,指定类型处理器

  • 使用xml写sql时

    <insert id="insertByXml">
        insert into employee(`name`, `age`, `gender`, `motto`)
        values (#{e.name}, #{e.age}, #{e.gender,typeHandler=com.example.mybatis.handler.GenderEnumHandler}, #{e.motto})
    </insert>
        
    <select id="selectByXml" resultMap="selectByXmlRM">
        select `name`, age, gender, motto
        from employee
        order by id desc limit 1
    </select>
    
    <resultMap id="selectByXmlRM" type="com.example.mybatis.model.Employee">
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="gender" column="gender" typeHandler="com.example.mybatis.handler.GenderEnumHandler"/>
        <result property="motto" column="motto"/>
    </resultMap>
    
  • 使用注解写sql时

    @Insert("insert into employee(`name`, `age`, `gender`, `motto`) values "
            + "(#{e.name}, #{e.age}, #{e.gender,typeHandler=com.example.mybatis.handler.GenderEnumHandler}, #{e.motto})")
    int insert(@Param("e") Employee e);
    
    @Select("select `name`,age,gender,motto from employee order by id desc limit 1")
    @Results(value = {
            // 其余查询列没有啥特殊性的,可不指定@Result,也是能正常查出来的(,当然,你非要指定也可以)
            @Result(column = "gender", property = "gender", typeHandler = GenderEnumHandler.class),
    })
    Employee select();
    

    相关资料

以上是关于mybatis自定义类型处理器的主要内容,如果未能解决你的问题,请参考以下文章

mybatis扩展之自定义类型处理器处理枚举类型

关于Mybatis中使用自定义类型通过 自定义TypeHandler类型处理器进行类型转换的两种配置方案-枚举类型示例

在python 3.6中处理自定义编码时遇到类型错误

使用mybatis中的自定义TypeHandler处理PostgreSQL中的Json类型字段

Mybatis -- MyBatis核心配置文件深入: typeHandlers标签(自定义类型转换器)plugins标签(插件标签:扩展mybatis功能 分页助手)

MyBatis使用自定义TypeHandler转换类型