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

相关文章

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

SQL BETWEEN 语句的基本用法详解

《SQLBETWEEN语句的基本用法详解》SQLBETWEEN语句是一个用于在SQL查询中指定查询条件的重要工具,它允许用户指定一个范围,用于筛选符合特定条件的记录,本文将详细介绍BETWEEN语... 目录概述BETWEEN 语句的基本用法BETWEEN 语句的示例示例 1:查询年龄在 20 到 30 岁

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

MySQL MCP 服务器安装配置最佳实践

《MySQLMCP服务器安装配置最佳实践》本文介绍MySQLMCP服务器的安装配置方法,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下... 目录mysql MCP 服务器安装配置指南简介功能特点安装方法数据库配置使用MCP Inspector进行调试开发指

SQLite3命令行工具最佳实践指南

《SQLite3命令行工具最佳实践指南》SQLite3是轻量级嵌入式数据库,无需服务器支持,具备ACID事务与跨平台特性,适用于小型项目和学习,sqlite3.exe作为命令行工具,支持SQL执行、数... 目录1. SQLite3简介和特点2. sqlite3.exe使用概述2.1 sqlite3.exe

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2