随笔 - 1162  文章 - 0  评论 - 16  阅读 - 59万 

一、TypeHandler

  TypeHandler 在MyBatis中进行数据库类型和JavaBean类型的映射。

  TypeHandler<T> 接口:

 

     该接口中声明了四个抽象方法,说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
//将parameter对象转换为字符串存入到 ps 对象的i位置
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
 
//从结果集中获取数据库对应查询结果
//将字符串还原为原始的T类型对象
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;

  

  BaseHandler<T> 类:

 

     BaseTypeHandler 抽象类实现了上面的四个抽象方法,做了简单的包装,然后又留出四个抽象方法。

 

  TypeHandle 的子类:

    

 

  所有的类型处理器都直接或间接继承了 TypeHandler类。

 

二、MyBatis 处理枚举类型

  如果我们在 Employee 中又新增一个枚举类型的属性来表示员工的状态,那么在 MyBatis 里面会如何保存的呢?

  员工状态枚举类 EmpStatus:

复制代码
public enum EmpStatus {
    LOGIN(100, "用户登录"),
    LOGOUT(200, "用户退出"),
    REMOVE(300, "用户不存在");

    private Integer code;
    private String msg;

    private EmpStatus(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    //根据状态码返回枚举对象
    public static EmpStatus getEmpStatusByCode(Integer code) {
        switch (code) {
            case 100:
                return LOGIN;
            case 200:
                return LOGOUT;
            case 300:
                return REMOVE;
            default:
            return LOGOUT;
        }
    }
}
复制代码

 

  Employee 类:

复制代码
public class Employee {
    private Integer id;
    private String lastName;
    private String gender;
    private String email;
    private EmpStatus empStatus = EmpStatus.LOGOUT;
}
复制代码

 

  接口中添加方法:

public Long addEmp(Employee employee);

 

  SQL映射文件配置:

复制代码
    <!--
        public Long addEmp(Employee employee);
    -->
    <insert id="addEmp" parameterType="com.njf.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id">
        insert into tbl_employee(`last_name`, `email`, `gender`, `empStatus`)
        values(#{lastName}, #{email}, #{gender}, #{empStatus})
    </insert>
复制代码

 

  测试:

复制代码
    @Test
     public void testEnum() throws IOException {
          //1、获取 sqlSessionFactory
          SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();

          //2、获取 sqlSession 实例,获取批量执行器
          SqlSession sqlSession = sqlSessionFactory.openSession();
          try {
               //3、获取接口的实现类对象
               EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);

               Employee emp = new Employee(null, "test_enum", "1", "enum@126.com", EmpStatus.LOGIN);
               employeeMapper.addEmp(emp);

               sqlSession.commit();


          } finally {
               sqlSession.close();
          }
     }
复制代码

 

  运行结果:

 

   可以看到默认情况下MyBatis处理枚举类型使用的是 EnumTypeHandler。

 

   如果要使用 EnumOrdinalTypeHandler 类型呢?

 

 

   可以看到如果配置的 EnumOridnalTypeHandler 类型处理器,保存的就会是枚举的索引值?

  如何配置呢?

  在 MyBatis 的核心配置文件中配置如下内容:

    <typeHandlers>
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.njf.mybatis.bean.EmpStatus" />
    </typeHandlers>

 

  测试效果:

 

 

   这是在数据库保存的就是枚举的索引值了。

  小结:

  默认myBatis在处理枚举的时候保存的是枚举的名字:EnumTypeHandler。

  改变使用:EnumOrdinalTypeHandler,在核心配置文件中进行设置

1
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.njf.mybatis.bean.EmpStatus" />

  

 

三、自定义 TypeHandler 处理枚举

  如果我们想要自己自定义保存的数据呢?

  我们可以通过自定义TypeHandler的形式来在设置参数或者取出结果集的时候自定义参数封装策略。

  步骤:

  (1)实现TypeHandler接口或者继承BaseTypeHandler;

  (2)使用@MappedTypes定义处理的java类型,使用@MappedJdbcTypes定义jdbcType类型;

  (3)在自定义结果集标签或者参数处理的时候声明使用自定义TypeHandler进行处理或者在全局配置TypeHandler要处理的javaType

  自定义枚举类型的 TypeHandler:

复制代码
/**
 *
 * 1、实现 TypeHandler<T> 接口或者继承 BaseTypeHandler<T>
 */
public class MyEnumEmpStatusTypeHandler implements TypeHandler<EmpStatus> {

    /**
     *  定义当前数据如何保存到数据库中
     * @param ps
     * @param i
     * @param parameter
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setParameter(PreparedStatement ps, int i, EmpStatus parameter, JdbcType jdbcType) throws SQLException {
        System.out.println("要保存的状态码:" + parameter.getCode());
        ps.setString(i, parameter.getCode().toString());
    }

    @Override
    public EmpStatus getResult(ResultSet rs, String columnName) throws SQLException {
        int code = rs.getInt(columnName);
        //需要根据从数据库中拿到的枚举状态码返回一个枚举对象
        EmpStatus empStatus = EmpStatus.getEmpStatusByCode(code);
        return empStatus;
    }

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

    @Override
    public EmpStatus getResult(CallableStatement cs, int columnIndex) throws SQLException {
        int code = cs.getInt(columnIndex);
        EmpStatus empStatus = EmpStatus.getEmpStatusByCode(code);
        return empStatus;
    }
}
复制代码

 

 

  在 MyBatis 的核心配置文件中进行配置:

复制代码
    <typeHandlers>
        <!--
            1、配置自定义的TypeHandler
            2、也可以在处理某个字段的时候告诉 MyBatis 用什么类型的处理器
                保存:#{empStatus, typeHandler="xxx"}
                查询:使用自定义 resultMap 使用 Handler

                注意:如果在参数位置修改TypeHandler,应该保证保存数据和查询数据使用的TypeHandler一样。
        -->
        <typeHandler handler="com.njf.mybatis.typeHandler.MyEnumEmpStatusTypeHandler" javaType="com.njf.mybatis.bean.EmpStatus" />
    </typeHandlers>
复制代码

 

  其他方式:

  保存的时候给字段执行处理器:

复制代码
    <!--
        public Long addEmp(Employee employee);
    -->
    <insert id="addEmp" parameterType="com.njf.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id">
        insert into tbl_employee(`last_name`, `email`, `gender`, `empStatus`)
        values(#{lastName}, #{email}, #{gender}, #{empStatus, typeHandler="全类名"})
    </insert>
复制代码

 

  在查询的时候通过自定义 resultMap 来给字段指定处理器:

复制代码
    <resultMap id="MyEmp" type="com.njf.mybatis.bean.Employee">
        <id column="id" property="id"/>
        <result column="empStatus" property="empStatus" typeHandler="com.njf.mybatis.typeHandler.MyEnumEmpStatusTypeHandler"/>
    </resultMap>


    <select id="getEmpById" resultMap="MyEmp">
        select id, last_name lastName, email, gender, empStatus from tbl_employee where id = #{id}
    </select>
复制代码

 

 

  测试插入与查询:

复制代码
     @Test
     public void testEnum() throws IOException {
          //1、获取 sqlSessionFactory
          SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();

          //2、获取 sqlSession 实例,获取批量执行器
          SqlSession sqlSession = sqlSessionFactory.openSession();
          try {
               //3、获取接口的实现类对象
               EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);

               //Employee emp = new Employee(null, "test_enum", "1", "enum@126.com", EmpStatus.LOGIN);
               //employeeMapper.addEmp(emp);

               sqlSession.commit();

               Employee empById = employeeMapper.getEmpById(13);
               System.out.println("empById = " + empById);
               System.out.println("员工状态:" + empById.getEmpStatus());

          } finally {
               sqlSession.close();
          }
     }
复制代码

 

  运行结果:

 

 

   可以看到数据库保存的是我们自定义的值。

 

   控制台打印的也是根据 code 获取的枚举类型。

 

posted on   格物致知_Tony  阅读(519)  评论(0编辑  收藏  举报
编辑推荐:
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
历史上的今天:
2019-09-19 数组模拟队列
2019-09-19 队列
点击右上角即可分享
微信分享提示

目录导航