开发者

一文搞懂MyBatis中TypeHandler机制

开发者 https://www.devze.com 2025-08-30 10:28 出处:网络 作者: 独泪了无痕
目录前言一、TypeHandler基础1.1 什么是 TypeHandler1.2 TypeHandler的工作原理二、TypeHandler 的应用2.1 TypeHandler 接口2.2 BaseTypeHandler 抽象类三、自定义类型处理器3.1 创建自定义 TypeHandler3.2 注册自定
目录
  • 前言
  • 一、TypeHandler基础
    • 1.1 什么是 TypeHandler
    • 1.2 TypeHandler的工作原理
  • 二、TypeHandler 的应用
    • 2.1 TypeHandler 接口
    • 2.2 BaseTypeHandler 抽象类
  • 三、自定义类型处理器
    • 3.1 创建自定义 TypeHandler
    • 3.2 注册自定义 TypeHandler
    • 3.3 使用自定义 TypeHandler
  • 四、小结

    前言

    在进行项目开发时,我们经常需要处理各种类型的数据转换问题。特别是在使用数据库时,常常会遇到需要将数据库中的字符串字段与 Java 对象之间的复杂转换。MyBATis 是一种流行的持久层框架,它提供了强大的数据访问功能,同时与 Spring Boot 等微服务技术栈无缝集成。为了解决这一问题,MyBatis 提供了一个强大的机制——TypeHandler,其是 MyBatis 中一个用于处理 Java 类型和数据库类型转换的组件,它在 MyBatis 进行参数设置和结果映射时起着至关重要的作用。本文将详细介绍TypeHandler 的使用方法,包括自定义 TypeHandler 的创建和注册,以及在实际项目中的应用示例。

    一、TypeHandler基础

    1.1 什么是 TypeHandler

    在 MyBatis 中,TypeHandler (类型处理器)用于处理 Java 类型和 JDBC 类型之间的映射和转换。例如,当数据库中的字段是 jsON 字符串时,可以将其转化为 Java 对象。每当 MyBatis 在执行 SQL 操作时,都会使用 TypeHandler 来确保数据类型的正确转换。在执行 SQL 语句时,TypeHandler 将 Java 类型转换为数据库可以理解的类型。在读取数据库结果时,TypeHandler 将数据库类型转换回 Java 类型。这一过程对于开发者是透php明的,由 MyBatis 框架内部自动完成。

    在 Mybatis 中给我们内置提供了多种常用的类型处理器,这也就是为什么我们在日常开发过程中,不需要关心 Java 和数据库之间的类型问题,Java 代码和 mysql 等数据库之间却能自动进行转化的原因。

    一文搞懂MyBatis中TypeHandler机制

    1.2 TypeHandler的工作原理

    TypeHandler 在 MyBatis 中是一个核心概念,其工作原理主要涉及Java类型和JDBC类型之间的映射和转换。

    • 当MyBatis执行一个预编译的SQL语句(如INSERT、UPDATE等)时,它需要将Java对象中的属性值设置到SQL语句中对应的占位符上
      1. MyBatis会根据映射配置找到对应的TypeHandler实例,这个映射配置可以在MyBatis的配置文件或者Mapper的XML文件中定义。
      2. TypeHandler实例会接收到Java对象中的属性值,并将其转换为JDBC能够识别的类型,这个转换过程是根据Java类型和JDBC类型之间的映射关系来实现的。
      3. 转换后的值会被设置到PreparedStatement对象中对应的占位符上,以便数据库能够正确解析和执行SQL语句。
    • 当数据库执行查询操作并返回结果集时,MyBatis需要将结果集中的数据提取出来,并转换为Java对象中的对应属性类型
      1. MyBatis会根据映射配置找到对应的TypeHandler实例。
      2. TypeHandler实例会从ResultSet对象中提取数据,这个提取过程是根据数据库字段和Java属性之间的映射关系来实现的。
      3. 提取出的数据会被转换为Java对象中的对应属性类型,这个转换过程同样是根据Java类型和JDBC类型之间的映射关系来实现的。
      4. 转换后的值会被设置到Java对象中对应的属性上,以便应用程序能够正确处理和使用这些数据。

    二、TypeHandler 的应用

    2.1 TypeHandler 接口

    TypeHandler 是类型转换器的顶层接口,其定义了类型转换器应该具有的功能,通常用于 MyBatis 在设置预处理语句(PreparedStatement)中的参数时,完成 JAVA 类型到 JDBC 类型的转换(通常用在#{}参数占位符中),以及在将查询到的结果记录映射到 JAVA 实体对象时,完成 JDBC 类型到 JAVA 类型的转换(通常用在<result>标签中)。以下是 TypeHandler 接口的一个基本概述:

    public interface TypeHandler<T> {
      /**
       * 用于设置PreparedStatement对象的指定参数。
       *
       * @param ps 当前的PreparedStatement对象 
       * @param i 当前参数的位置 
       * @param parameter 当前参数的Java对象 
       * @param jdbcType 当前参数的数据库类型 
       */
    	void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
      
      /**
       * 从结果集中根据列名获取数据并转换为 java 对象
       *
       * @param rs 当前的结果集 
       * @param columnName 当前的字段名称 
       */
    	T getResult(ResultSet rs, String columnName) throws SQLException;
      
      /**
       * 从结果集中根据列索引获取数据并转换为 java 对象
       *
       * @param rs 当前的结果集 
       * @param columnIndex 当前字段的位置
       */
    	T getResult(ResultSet rs, int columnIndex) throws SQLException;
    
      /**
       * 从存储过程的结果集中根据列索引获取数据并转换为对应的Java类型
       *
       * @param cs 当前的CallableStatement执行后的CallableStatement 
       * @param columnIndex 当前输出参数的位置 
       */
    	T getResult(CallableStatement cs, int columnIndex) throws SQLException;
    }
    

    对于基本数据类型(如int、long、float等),MyBatis提供了内置的 TypeHandler 实现,这些实现能够直接将 Java 基本数据类型转换为对应的 JDBC 基本数据类型,反之亦然。在 MyBatis 的 TypeHandlerRegistry 类型中,可以看到内置的类型处理器,这里整理常见的一些。

    TypeHandler描述
    BaseTypeHandler基础类型处理器,用于处理Java基础类型和JDBC类型之间的转换,如Integer、String等。
    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数组类型处理器,用于处理Java数组类型和JDBC数组类型之间的转换。
    CollectionTypeHandler集合类型处理器,用于处理Java集合类型和JDBC集合类型之间的转换。

    以上只是 MyBatis 内置 TypeHandler 的一部分示例,实际上 MyBatis 提供了更多的内置 TypeHandler 以支持各种不同类型的数据转换需求。在使用 MyBatis 时,可以根据具体的数据库类型和 Java 类型选择合适的内置 TypeHandler,或者根据需要自定义 TypeHandler 来处理特殊的数据类型转换场景。

    2.2 BaseTypeHandler 抽象类

    实际开发中,我们可以继承 org.apache.ibatis.type.BaseTypeHandler 类型来实现自定义类型处理器。这个类型是抽象类型,实现了 TypeHandler 的方法进行通用流程的封装,做了异常处理,并定义了几个类似的抽象方法,使得创建自定义类型处理器时只需要覆盖必要的方法。通常,如果不需要处理所有的JDBC类型,可以选择继承 BaseTypeHandler,可以极大地降低开发难度。BaseTypeHandler 提供了对 null 值的处理以及部分 TypeHandler 接口方法的默认实现。当继承 BaseTypeHandler 时,通常需要实现或覆盖以下方法:

    一文搞懂MyBatis中TypeHandler机制

    // 设置非空的参数值,实现类需要覆盖这个方法来设置非空参数。
    void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;
    
    // 根据列名获取可能为null的结果,实现类需要覆盖这个方法来获取可能为空的结果。
    T getNullableResult(ResultSet var1, String var2) throws SQLException;
    
    // 根据列索引获取可能为null的结果,实现类需要覆盖这个方法来获取可能为空的结果。
    T getNullableResult(ResultSet var1, int var2) throws SQLException;
    
    // 从存储过程的结果集中根据列索引获取可能为null的结果,实现类需要覆盖这个方法来获取可能为空的结果。
    T getNullableResult(CallableStatement var1, int var2) throws SQLException;
    

    这些方法专注于处理非空值的转换以及处理从数据库中检索的可能为null的值,总的来说,TypeHandler 接口提供了完整的 JDBC 类型和 Java 类型转换的契约,而 BaseTypeHandler 则是一个便利的基类,提供了一些基本的和通用的实现,以减少自定义类型处理器时的代码量。在创建自定义类型处理器时,可以根据具体需求选择直接实现 TypeHandler 接口还是继承 BaseTypeHandler 类。

    三、自定义类型处理器

    尽管 MyBatis 提供了一系列内置的 TypeHandler,用于处理常见的 Java 类型与数据库类型之间的转换。但在某些特殊情况下,可能需要自定义 TypeHandler 来实现任意复杂的类型转换逻辑。可以通过实现 TypeHandler 接口或继承 BaseTypeHandler 类来创建自定义的TypeHandler实现,以满足特定业务需求。

    3.1 创建自定义 TypeHandler

    我们可以创建一个来自动转义字符串内容,现在我们创建一个 EscapedStringTypeHandler 来处理类型的转义、反转义,需要实现 org.apache.ibatis.type.TypeHandler 接口或者继承一个很便利的类 org.apache.ibatis.typHNSFfBDe.BaseTypeHandler

    import cn.hutool.http.htmlUtil;
    import org.apache.ibatis.type.BaseTypeHandlpythoner;
    import org.apache.ibatis.type.JdbcType;
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import static org.apache.ibatis.type.JdbcType.*;
    
    @MappedTypes(String.class)// 指定该Handler对应的Java类型
    @MappedJdbcTypes(value = {CLOB,CLOB,VARCHAR,LONGVARCHAR,NVARCHAR,NCHAR,NCLOB}, includeNullJdbcType = true) // 指定对应的JDBC类型
    public class EscapedStringTypeHandler extends BaseTypeHandler<String> {
        @Override
        public void setNonNullParameter(PreparedStatement ps, int i,
                                        String parameter, JdbcType jdbcType) throws SQLException {
            // 对原数据不做处理
            ps.setString(i, parameter);
        }
    
        @Override
        public String getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
            String data = resultSet.getString(columnName);
            return StrUtil.isNotBlank(data) ? HtmlUtil.unescape(data) : null;
        }
    
        @Override
        public String getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
            String data = resultSet.getString(columnIndex);
            return StrUtil.isNotBlank(data) ? HtmlUtil.unescape(data) : null;
        }
    
        @Override
        public String getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
            String data = callableStatement.getString(columnIndex);
            return StrUtil.isNotBlank(data) ? HtmlUtil.unescape(data) : null;
        }
    }
    

    使用上述的类型处理器将会覆盖已经存在的处理 Java 的 String 类型属性和 VARCHAR 参数及结果的类型处理器。 要注意 MyBatis 不会通过窥探数据库元信息来决定使用哪种类型,所以你必须在参数和结果映射中指明那是 VARCHAR 类型的字段, 以使其能够绑定到正确的类型处理器上。这是因为 MyBatis 直到语句被执行时才清楚数据类型。

    3.2 注册自定义 TypeHandler

    此外,MyBatphpis 还提供了丰富的 API 和扩展点来支持开发者自定义 TypeHandler 的注册和使用方式。我们可以通过配置文件、注解或编程方式将自定义的 TypeHandler 注册到MyBatis 中,如果是在 Spring Boot 环境中使用 MyBatis,可以在 application.yml 文件中,配置属性来指定 TypeHandler 所在的包路径,MyBatis 会自动扫描并注册该包下的所有TypeHandler。以下是配置示例:

    mybatis:
      type-handlers-package: com.dllwh.handler # 指定自定义TypeHandler的包位置
    

    3.3 使用自定义 TypeHandler

    接下来,我们在 Mapper 的 XML 映射文件中,通过 result 或 parameterType 属性引用它们来处理特定的数据类型转换需求。以下是配置示例:

    <!-- Mapper XML中使用 -->
    <resultMap id="personMap" type="person">
      <id property="id" column="id" />
      <!-- 指定typeHandler属性为全类名-->
      <result property="name" column="name" typeHandler="org.dllwh.handler.EscapedStringTypeHandler"/>/>
    </resultMap>
    
    <!www.devze.com-- Mapper XML中使用 -->
    <select id="selectByExample" resultType="CustomJavaType">
        SELECT * FROM table WHERE user_name = #{value, typeHandler=org.dllwh.handler.EscapedStringTypeHandler}
    </select>
    

    四、小结

    TypeHandler 在 MyBatis 中扮演着非常重要的角色,它负责处理数据库数据结构和bean对象数据类型之间的转换。通过创建自定义的 TypeHandler,我们能够灵活地处理 MyBatis 中复杂数据类型的转换问题,提高开发效率和代码可维护性。无论是 JSON、XML 还是其他复杂类型,自定义 TypeHandler 都能提供统一且方便的方式来实现这一目标。在实际项目中,合理使用 TypeHandler 能够使数据映射更加清晰与高效,尤其是 Spring Boot 项目中,更是简化了配置和注册过程,使得开发者能够更专注于业务逻辑的实现。

    到此这篇关于一文搞懂MyBatis中TypeHandler机制的文章就介绍到这了,更多相关MyBatis TypeHandler内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号