MyBatis TypeHandler详解:原理与自定义实践

2024-03-03 18:36

本文主要是介绍MyBatis TypeHandler详解:原理与自定义实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在MyBatis中,TypeHandler扮演着一个至关重要的角色,它负责Java类型和JDBC类型之间的映射和转换。本文将详细介绍MyBatis TypeHandler的概念、工作原理,以及如何在Spring Boot环境中自定义TypeHandler,并通过案例来展示其应用场景。

目录

    • 一、TypeHandler简介
    • 二、TypeHandler的工作原理
      • 1. 设置参数(Parameter Setting)
      • 2. 获取结果(Result Getting)
      • 3. 类型映射和转换规则
      • 4. 自定义TypeHandler的扩展性
    • 三、内置TypeHandler介绍
    • 四、自定义TypeHandler实践
      • 1. 创建自定义TypeHandler类
        • `org.apache.ibatis.type.TypeHandler`
        • `org.apache.ibatis.type.BaseTypeHandler`
      • 2. 注册自定义TypeHandler
      • 3. 在Mapper中使用自定义TypeHandler
      • 自定义时间转换案例
    • 五、应用场景
    • 六、总结

一、TypeHandler简介

TypeHandler是MyBatis中用于处理Java类型与JDBC类型之间转换的接口。在SQL语句执行过程中,无论是设置参数还是获取结果集,都需要通过TypeHandler进行类型转换。MyBatis提供了丰富的内置TypeHandler实现,以支持常见的数据类型转换。同时,也可以根据需要自定义TypeHandler来处理特殊的数据类型或转换逻辑。

二、TypeHandler的工作原理

TypeHandler在MyBatis中是一个核心概念,其工作原理主要涉及Java类型和JDBC类型之间的转换。下面将详细介绍TypeHandler的工作原理。

1. 设置参数(Parameter Setting)

当MyBatis执行一个预编译的SQL语句(如INSERT、UPDATE等)时,它需要将Java对象中的属性值设置到SQL语句中对应的占位符上。这个过程就是通过TypeHandler来实现的。

具体步骤如下:

  • MyBatis会根据映射配置找到对应的TypeHandler实例。这个映射配置可以在MyBatis的配置文件或者Mapper的XML文件中定义。
  • TypeHandler实例会接收到Java对象中的属性值,并将其转换为JDBC能够识别的类型。这个转换过程是根据Java类型和JDBC类型之间的映射关系来实现的。
  • 转换后的值会被设置到PreparedStatement对象中对应的占位符上,以便数据库能够正确解析和执行SQL语句。

2. 获取结果(Result Getting)

当数据库执行查询操作并返回结果集时,MyBatis需要将结果集中的数据提取出来,并转换为Java对象中的对应属性类型。这个过程同样是通过TypeHandler来实现的。

具体步骤如下:

  • MyBatis会根据映射配置找到对应的TypeHandler实例。
  • TypeHandler实例会从ResultSet对象中提取数据,这个提取过程是根据数据库字段和Java属性之间的映射关系来实现的。
  • 提取出的数据会被转换为Java对象中的对应属性类型。这个转换过程同样是根据Java类型和JDBC类型之间的映射关系来实现的。
  • 转换后的值会被设置到Java对象中对应的属性上,以便应用程序能够正确处理和使用这些数据。

3. 类型映射和转换规则

TypeHandler的核心功能是实现Java类型和JDBC类型之间的映射和转换。这个映射和转换规则是根据Java类型和JDBC类型的特性和语义来定义的。

  • 对于基本数据类型(如int、long、float等),MyBatis提供了内置的TypeHandler实现,这些实现能够直接将Java基本数据类型转换为对应的JDBC基本数据类型,反之亦然。
  • 对于复杂数据类型(如自定义对象、集合等),MyBatis允许开发者自定义TypeHandler来实现复杂的类型转换逻辑。例如,开发者可以定义一个自定义的TypeHandler来将数据库中的JSON字符串转换为Java中的对象,或者将Java对象转换为JSON字符串存储到数据库中。

4. 自定义TypeHandler的扩展性

MyBatis的TypeHandler机制具有很高的扩展性。开发者可以通过实现TypeHandler接口或继承BaseTypeHandler类来创建自定义的TypeHandler实现。自定义的TypeHandler可以实现任意复杂的类型转换逻辑,以满足特定业务需求。

此外,MyBatis还提供了丰富的API和扩展点来支持开发者自定义TypeHandler的注册和使用方式。开发者可以通过配置文件、注解或编程方式将自定义的TypeHandler注册到MyBatis中,并在Mapper的XML映射文件中引用它们来处理特定的数据类型转换需求。

三、内置TypeHandler介绍

MyBatis为了简化开发者的工作,提供了一系列内置的TypeHandler,这些内置的TypeHandler能够处理大部分常见的数据类型转换。以下是一些MyBatis中常见的内置TypeHandler:

  1. BooleanTypeHandler
    处理Java的Boolean类型与数据库中的BOOLEANBIT等类型的映射关系。

  2. IntegerTypeHandlerLongTypeHandlerShortTypeHandler 等:
    这些TypeHandler分别处理Java中的IntegerLongShort等整数类型与数据库中的相应整数类型的映射,如INTBIGINTSMALLINT等。

  3. FloatTypeHandlerDoubleTypeHandlerBigDecimalTypeHandler
    处理Java中的浮点数和定点数类型,如FloatDoubleBigDecimal,与数据库中的FLOATDOUBLEDECIMAL等类型的映射。

  4. StringTypeHandler
    处理Java的String类型与数据库中的字符类型如VARCHARCHARTEXT等的映射关系。

  5. DateTypeHandlerTimeTypeHandlerTimestampTypeHandler
    这些TypeHandler处理Java中的日期和时间类型,如DateTimeTimestamp,与数据库中的DATETIMETIMESTAMP等类型的映射。

  6. ByteArrayTypeHandler
    处理Java的byte[]类型与数据库中的二进制类型的映射,如BLOBBINARY等。

  7. ClobTypeHandlerBlobTypeHandler
    分别处理Java中的Clob(字符大对象)和Blob(二进制大对象)类型与数据库中的CLOBBLOB类型的映射。

  8. EnumTypeHandlerEnumOrdinalTypeHandler
    这两个TypeHandler用于处理Java中的枚举类型。EnumTypeHandler将枚举名称存储到数据库,而EnumOrdinalTypeHandler将枚举的序数(ordinal)存储到数据库。

  9. JdbcTypeHandler
    这是一个通用的TypeHandler,它根据JDBC类型(java.sql.Types中的常量)来确定具体的类型处理方式。

  10. UnknownTypeHandler
    当MyBatis无法确定具体的类型处理方式时,会使用这个TypeHandler。通常,这是一个最后的备选方案,它会尝试将值作为对象(Object)来处理。

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

四、自定义TypeHandler实践

在某些情况下,我们可能需要处理一些特殊的数据类型或者实现复杂的类型转换逻辑。这时,就需要自定义TypeHandler。下面是在Spring Boot环境中自定义TypeHandler的步骤:

1. 创建自定义TypeHandler类

自定义TypeHandler需要实现org.apache.ibatis.type.TypeHandler接口,或者继承org.apache.ibatis.type.BaseTypeHandler类,并重写相应的方法。

org.apache.ibatis.type.TypeHandler

TypeHandler是一个接口,用于定义如何处理JDBC类型和Java类型之间的转换。当你需要创建一个自定义的类型处理器时,通常需要实现这个接口。这个接口定义了以下主要方法:

  1. setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType):用于设置PreparedStatement对象的指定参数。
  2. getResult(ResultSet rs, String columnName):从结果集中根据列名获取数据。
  3. getResult(ResultSet rs, int columnIndex):从结果集中根据列索引获取数据。
  4. getResult(CallableStatement cs, int columnIndex):从存储过程的结果集中根据列索引获取数据。

这些方法分别负责在SQL语句执行时将Java类型的参数转换成JDBC类型,以及在执行SQL查询后将JDBC类型的结果转换成Java类型。

org.apache.ibatis.type.BaseTypeHandler

BaseTypeHandler是TypeHandler接口的一个抽象实现类,它提供了一些基本的实现,使得创建自定义类型处理器时只需要覆盖必要的方法。通常,如果你不需要处理所有的JDBC类型,可以选择继承BaseTypeHandler以减少工作量。

BaseTypeHandler 提供了对null值的处理以及部分TypeHandler接口方法的默认实现。当你继承BaseTypeHandler时,通常需要实现或覆盖以下方法:

  1. setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType):设置非空的参数值。
  2. getNullableResult(ResultSet rs, String columnName):根据列名获取可能为null的结果。
  3. getNullableResult(ResultSet rs, int columnIndex):根据列索引获取可能为null的结果。
  4. getNullableResult(CallableStatement cs, int columnIndex):从存储过程的结果集中根据列索引获取可能为null的结果。

这些方法专注于处理非空值的转换以及处理从数据库中检索的可能为null的值。

总的来说,TypeHandler接口提供了完整的JDBC类型和Java类型转换的契约,而BaseTypeHandler则是一个便利的基类,提供了一些基本的和通用的实现,以减少自定义类型处理器时的代码量。在创建自定义类型处理器时,可以根据具体需求选择直接实现TypeHandler接口还是继承BaseTypeHandler类。

2. 注册自定义TypeHandler

在MyBatis的配置文件中注册自定义的TypeHandler。如果是在Spring Boot环境中使用MyBatis,可以通过在application.propertiesapplication.yml文件中配置mybatis.type-handlers-package属性来指定TypeHandler所在的包路径,MyBatis会自动扫描并注册该包下的所有TypeHandler。

3. 在Mapper中使用自定义TypeHandler

在Mapper的XML映射文件中,通过resultTypeparameterType属性引用自定义的TypeHandler。例如,在<select>标签中设置resultType="com.example.CustomType"来指定使用自定义的TypeHandler处理查询结果。

自定义时间转换案例

首先,创建一个自定义的TypeHandler来处理LocalDateTime类型与数据库中的时间戳类型之间的转换。

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 java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;@MappedJdbcTypes(JdbcType.TIMESTAMP) // 指定对应的JDBC类型
@MappedTypes(LocalDateTime.class) // 指定对应的Java类型
public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime parameter, JdbcType jdbcType) throws SQLException {ps.setTimestamp(i, java.sql.Timestamp.valueOf(parameter));}@Overridepublic LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {java.sql.Timestamp timestamp = rs.getTimestamp(columnName);return timestamp != null ? timestamp.toLocalDateTime() : null;}@Overridepublic LocalDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {java.sql.Timestamp timestamp = rs.getTimestamp(columnIndex);return timestamp != null ? timestamp.toLocalDateTime() : null;}@Overridepublic LocalDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {java.sql.Timestamp timestamp = cs.getTimestamp(columnIndex);return timestamp != null ? timestamp.toLocalDateTime() : null;}
}

然后,在Spring Boot的配置中,你需要确保MyBatis能够扫描到这个TypeHandler。通常,MyBatis会自动扫描与Mapper接口相同的包路径下的TypeHandler。但是,如果你想要更明确地指定TypeHandler的位置,你可以通过MyBatis的配置文件来做到这一点。

src/main/resources目录下创建MyBatis的配置文件mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><typeHandlers><package name="com.example.demo.typehandler"/> <!-- 指定TypeHandler的包名 --></typeHandlers>
</configuration>

application.propertiesapplication.yml中指定MyBatis配置文件的位置:

# application.properties
mybatis.config-location=classpath:mybatis-config.xml

确保你的Mapper接口使用了LocalDateTime类型的字段,并且你的数据库表中有对应的时间戳字段。

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.time.LocalDateTime;
import java.util.List;@Mapper
public interface ExampleMapper {@Select("SELECT * FROM example_table")List<ExampleEntity> selectAll();// 其他CRUD操作...
}// 对应的实体类
public class ExampleEntity {private Long id;private LocalDateTime createdAt;// 省略getter和setter方法...
}

最后,在Spring Boot的启动类或配置类上使用@MapperScan注解来指定Mapper接口所在的包名:

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.example.demo.mapper") // 指定Mapper接口所在的包名
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}

确保你的Spring Boot项目中包含了MyBatis和MyBatis Spring Boot Starter的依赖项。你可以在pom.xml中添加如下依赖:

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version> <!-- 使用适合你项目的版本 -->
</dependency>

现在,当你运行Spring Boot应用时,MyBatis将会使用你自定义的LocalDateTimeTypeHandler来处理LocalDateTime类型与数据库中的TIMESTAMP类型之间的转换。注意,由于我们使用了@MappedJdbcTypes@MappedTypes注解,MyBatis将自动识别并使用这个TypeHandler。如果你没有在TypeHandler上使用这些注解,你需要在MyBatis配置文件中显式注册TypeHandler

要在MyBatis中注册自定义的TypeHandler,你通常有两种方法:

  1. 使用注解:直接在TypeHandler类上使用@MappedJdbcTypes和@MappedTypes注解。这种方法在你已经使用的示例中展示了。当MyBatis扫描到带有这些注解的TypeHandler时,它会自动注册。
  2. 在MyBatis配置文件中注册:如果你没有使用注解,或者想要更明确地注册TypeHandler,你可以在MyBatis的配置文件中手动添加它。

五、应用场景

自定义TypeHandler的应用场景非常广泛。以下是一些常见的应用场景:

  1. 处理枚举类型:将数据库中的整数值映射为Java中的枚举类型,或者将枚举类型转换为数据库中的整数值。

  2. 处理复杂数据类型:如将数据库中的JSON字符串映射为Java中的对象,或者将Java对象转换为JSON字符串存储到数据库中。

  3. 实现特殊的类型转换逻辑:如将数据库中的日期字符串转换为Java中的特定日期对象格式。

  4. 兼容不同的数据库类型:当使用不同类型的数据库时,可能需要处理不同类型之间的转换差异。通过自定义TypeHandler可以实现数据库类型之间的兼容转换。

六、总结

MyBatis的TypeHandler机制为Java类型和JDBC类型之间的转换提供了灵活且强大的支持。通过内置和自定义的TypeHandler,我们可以轻松处理各种数据类型转换需求,提高开发效率和代码可维护性。在Spring Boot环境中使用自定义TypeHandler更是简化了配置和注册过程,使得开发者能够更专注于业务逻辑的实现。

这篇关于MyBatis TypeHandler详解:原理与自定义实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/770524

相关文章

将Mybatis升级为Mybatis-Plus的详细过程

《将Mybatis升级为Mybatis-Plus的详细过程》本文详细介绍了在若依管理系统(v3.8.8)中将MyBatis升级为MyBatis-Plus的过程,旨在提升开发效率,通过本文,开发者可实现... 目录说明流程增加依赖修改配置文件注释掉MyBATisConfig里面的Bean代码生成使用IDEA生

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

详解C#如何提取PDF文档中的图片

《详解C#如何提取PDF文档中的图片》提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使用,下面我们就来看看如何使用C#通过代码从PDF文档中提取图片吧... 当 PDF 文件中包含有价值的图片,如艺术画作、设计素材、报告图表等,提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定