Mybatis拦截器Interceptor与字段类型处理器BaseTypeHandler区别

本文主要是介绍Mybatis拦截器Interceptor与字段类型处理器BaseTypeHandler区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Mybatis拦截器Interceptor与字段类型处理器BaseTypeHandler区别

  • 1. 功能区别
  • 2. 使用场景
  • 3. 原理分析
  • 4. 使用方式
  • 5. 注意事项
  • 6. 参考资料

MyBatis 的拦截器(Interceptor)和自定义类型处理器(BaseTypeHandler 的子类)在功能、使用场景、使用方式和注意事项等方面有以下区别。

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

MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能。MyBatis拦截器可以做的工作:SQL修改,分页操作,数据过滤,SQL执行时间性能监控等。

1. 功能区别

  1. 拦截器

    • 主要用于拦截 MyBatis 的四大核心对象(Executor、StatementHandler、ParameterHandler、ResultSetHandler)的特定方法执行,实现对 SQL 执行过程的干预。
    • 可以在 SQL 执行的不同阶段进行操作,比如在执行 SQL 之前修改参数、在执行 SQL 之后处理结果等。
  2. 自定义类型处理器

    • 用于处理特定 Java 类型与特定数据库类型之间的转换。
    • 专注于 Java 对象和数据库值之间的数据类型转换。

2. 使用场景

  1. 拦截器

    • 日志记录:记录 SQL 执行的时间、参数和结果,以便进行性能分析和故障排查。
    • 缓存控制:实现自定义的缓存策略,提高查询性能。
    • 安全控制:在 SQL 执行前进行权限检查,防止未经授权的访问。
    • 动态 SQL 构建:根据特定条件动态修改 SQL 语句。
  2. 自定义类型处理器

    • 处理数据库中不常见的数据类型或自定义数据类型与 Java 对象之间的转换。
    • 当 MyBatis 内置的类型处理器无法满足特定类型的转换需求时,例如处理特定格式的日期时间类型、自定义枚举类型等。

3. 原理分析

  1. 拦截器原理分析
    MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
概括一下,分别是拦截执行器、参数控制器、结果控制器、SQL语句构建控制器,对执行流程进行更改.对应四个对象.

  1. 字段类型处理器原理分析

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

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

setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType):用于设置PreparedStatement对象的指定参数。
getResult(ResultSet rs, String columnName):从结果集中根据列名获取数据。
getResult(ResultSet rs, int columnIndex):从结果集中根据列索引获取数据。
getResult(CallableStatement cs, int columnIndex):从存储过程的结果集中根据列索引获取数据。
这些方法分别负责在SQL语句执行时将Java类型的参数转换成JDBC类型,以及在执行SQL查询后将JDBC类型的结果转换成Java类型。

4. 使用方式

使用拦截器与BaseTypeHandler方式实现,将Java类型LocalDateTime(LocalDateTime默认纳秒9位,Time is represented to nanosecond precision.)转为MySQL类型timestamp。

  1. 拦截器

    • 定义一个实现Interceptor接口的类,并使用@Intercepts注解指定要拦截的对象和方法。
    • 在 MyBatis 配置文件中注册拦截器,或者通过编程方式将拦截器添加到Configuration对象中。

    示例代码:

     import org.apache.ibatis.executor.Executor;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Plugin;import org.apache.ibatis.plugin.Signature;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.reflection.SystemMetaObject;import java.lang.reflect.Field;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.Properties;@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),// @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})public class ParameterInterceptor implements Interceptor {private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];Object parameter = null;BoundSql boundSql = mappedStatement.getBoundSql(parameter);// 获取参数if (invocation.getArgs().length > 1) {parameter = invocation.getArgs()[1];}// 获取 MetaObject,用于反射操作MetaObject metaObject = SystemMetaObject.forObject(parameter);// 遍历所有字段Field[] fields = parameter.getClass().getDeclaredFields();for (Field field : fields) {field.setAccessible(true);Object fieldValue = metaObject.getValue(field.getName());if (fieldValue instanceof LocalDateTime) {LocalDateTime localDateTime = (LocalDateTime)fieldValue;String formattedDate = localDateTime.format(FORMATTER);metaObject.setValue(field.getName(), LocalDateTime.parse(formattedDate, FORMATTER));}}// 继续执行原方法return invocation.proceed();}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}/*** 处理配置文件中的参数** @param properties 配置*/@Overridepublic void setProperties(Properties properties) {Interceptor.super.setProperties(properties);}}
    

    全局字段转换在mybatis-config.xml配置文件中注册:

    <configuration><plugins><plugin interceptor="your.package.MyInterceptor"></plugin></plugins>
    </configuration>
    
  2. 自定义类型处理器

    • 继承BaseTypeHandler类,并实现其中的抽象方法,根据需要进行类型转换。
    • 使用@MappedJdbcTypes@MappedTypes注解指定处理的 JDBC 类型和 Java 类型。
    • 在 MyBatis 配置文件中注册类型处理器,或者通过编程方式将其添加到Configuration对象中。

    示例代码:

     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.sql.Timestamp;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;@MappedJdbcTypes(JdbcType.TIMESTAMP)@MappedTypes(LocalDateTime.class)public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");@Overridepublic void setNonNullParameter(PreparedStatement preparedStatement, int i, LocalDateTime localDateTime, JdbcType jdbcType) throws SQLException {String formattedDateTime = localDateTime.format(FORMATTER);Timestamp timestamp = Timestamp.valueOf(formattedDateTime);preparedStatement.setTimestamp(i, timestamp);}@Overridepublic LocalDateTime getNullableResult(ResultSet resultSet, String columnName) throws SQLException {Long timestamp = resultSet.getLong(columnName);if (resultSet.wasNull()) {return null;}String timestampString = String.valueOf(timestamp);return LocalDateTime.parse(timestampString, FORMATTER);}@Overridepublic LocalDateTime getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {Long timestamp = resultSet.getLong(columnIndex);if (resultSet.wasNull()) {return null;}String timestampString = String.valueOf(timestamp);return LocalDateTime.parse(timestampString, FORMATTER);}@Overridepublic LocalDateTime getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {Long timestamp = callableStatement.getLong(columnIndex);if (callableStatement.wasNull()) {return null;}String timestampString = String.valueOf(timestamp);return LocalDateTime.parse(timestampString, FORMATTER);}}
    

全局字段转换在mybatis-config.xml配置文件中注册:

<configuration><typeHandlers><typeHandler handler="your.package.LocalDateTimeTypeHandler"/></typeHandlers>
</configuration>

或者SqlSessionFactory 全局配置SqlSessionFactory.setTypeHandlers(new LocalDateTimeTypeHandler());

mapper.xml配置,单个字段转换,单个字段转换:指定jdbcType、javaType与typeHandler

<result property="orderTime" column="order_time" typeHandler="your.package.LocalDateTimeTypeHandler"/>

或者
#{orderTime,typeHandler=your.package.LocalDateTimeTypeHandler}

5. 注意事项

  1. 拦截器

    • 拦截器可能会影响性能,尤其是在频繁执行的 SQL 操作中,因为拦截器会增加额外的处理逻辑。
    • 谨慎使用拦截器,确保拦截的逻辑不会破坏 MyBatis 的正常执行流程。
    • 多个拦截器的执行顺序可能会影响结果,需要注意拦截器的注册顺序。
  2. 自定义类型处理器

    • 确保类型处理器的正确性和稳定性,特别是在处理边界情况和异常情况时。
    • 不同的数据库对于特定类型的处理可能会有所不同,需要进行充分的测试以确保兼容性。
    • 如果可能,尽量使用 MyBatis 内置的类型处理器,只有在必要时才创建自定义类型处理器。

6. 参考资料

https://www.bookstack.cn/read/MyBatis-zh-3.4/typeHandlers
https://blog.csdn.net/qq_26664043/article/details/136358934
https://cloud.tencent.com/developer/article/2398586
https://developer.aliyun.com/article/1549764
https://baomidou.com/guides/type-handler/
https://blog.csdn.net/wb1046329430/article/details/111501755
https://www.cnblogs.com/Courage129/p/14121453.html

这篇关于Mybatis拦截器Interceptor与字段类型处理器BaseTypeHandler区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Mybatis对MySQL if 函数的不支持问题解读

《Mybatis对MySQLif函数的不支持问题解读》接手项目后,为了实现多租户功能,引入了Mybatis-plus,发现之前运行正常的SQL语句报错,原因是Mybatis不支持MySQL的if函... 目录MyBATis对mysql if 函数的不支持问题描述经过查询网上搜索资料找到原因解决方案总结Myb

MySQL 筛选条件放 ON后 vs 放 WHERE 后的区别解析

《MySQL筛选条件放ON后vs放WHERE后的区别解析》文章解释了在MySQL中,将筛选条件放在ON和WHERE中的区别,文章通过几个场景说明了ON和WHERE的区别,并总结了ON用于关... 今天我们来讲讲数据库筛选条件放 ON 后和放 WHERE 后的区别。ON 决定如何 "连接" 表,WHERE

mybatis-plus分表实现案例(附示例代码)

《mybatis-plus分表实现案例(附示例代码)》MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生,:本文主要介绍my... 目录文档说明数据库水平分表思路1. 为什么要水平分表2. 核心设计要点3.基于数据库水平分表注意事项示例

Mybatis的mapper文件中#和$的区别示例解析

《Mybatis的mapper文件中#和$的区别示例解析》MyBatis的mapper文件中,#{}和${}是两种参数占位符,核心差异在于参数解析方式、SQL注入风险、适用场景,以下从底层原理、使用场... 目录MyBATis 中 mapper 文件里 #{} 与 ${} 的核心区别一、核心区别对比表二、底

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

MyBatis配置文件中最常用的设置

《MyBatis配置文件中最常用的设置》文章主要介绍了MyBatis配置的优化方法,包括引用外部的properties配置文件、配置外置以实现环境解耦、配置文件中最常用的6个核心设置以及三种常用的Ma... 目录MyBATis配置优化mybatis的配置中引用外部的propertis配置文件⚠️ 注意事项X

MyBatis中的两种参数传递类型详解(示例代码)

《MyBatis中的两种参数传递类型详解(示例代码)》文章介绍了MyBatis中传递多个参数的两种方式,使用Map和使用@Param注解或封装POJO,Map方式适用于动态、不固定的参数,但可读性和安... 目录✅ android方式一:使用Map<String, Object>✅ 方式二:使用@Param

C# Semaphore与SemaphoreSlim区别小结

《C#Semaphore与SemaphoreSlim区别小结》本文主要介绍了C#Semaphore与SemaphoreSlim区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录一、核心区别概览二、详细对比说明1.跨进程支持2.异步支持(关键区别!)3.性能差异4.API 差

Java中自旋锁与CAS机制的深层关系与区别

《Java中自旋锁与CAS机制的深层关系与区别》CAS算法即比较并替换,是一种实现并发编程时常用到的算法,Java并发包中的很多类都使用了CAS算法,:本文主要介绍Java中自旋锁与CAS机制深层... 目录1. 引言2. 比较并交换 (Compare-and-Swap, CAS) 核心原理2.1 CAS