当前位置: 首页 > news >正文

Mybatis拦截器介绍及其应用

Mybatis拦截器介绍及其应用

1、介绍

Mybatis拦截器设计的初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。通过Mybatis拦截器我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。所以Mybatis拦截器的使用范围是非常广泛的。

2、Mybatis部分核心对象

Mybatis核心对象解释
SqlSession作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
ExecutorMyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
StatementHandler封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合
ParameterHandler负责对用户传递的参数转换成JDBC Statement 所需要的参数
ResultSetHandler负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
TypeHandler负责java数据类型和jdbc数据类型之间的映射和转换
MappedStatementMappedStatement维护了一条mapper.xml文件里面 select 、update、delete、insert节点的封装
SqlSource负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
BoundSql表示动态生成的SQL语句以及相应的参数信息
ConfigurationMyBatis所有的配置信息都维持在Configuration对象之中

3、拦截器种类

3.1、ParameterHandler 参数拦截器:

ParameterHandler拦截器类型用于拦截MyBatis的参数处理过程。它在参数设置到PreparedStatement对象之前拦截并修改参数。你可以通过实现ParameterHandler接口来自定义参数处理逻辑,例如对参数进行加密、解密、校验或转换等操作。

3.2、ResultSetHandler 结果集拦截器:

ResultSetHandler拦截器类型用于拦截MyBatis的结果集处理过程。它在从JDBC结果集中获取数据并映射到Java对象或集合之前拦截并修改结果。你可以通过实现ResultSetHandler接口来自定义结果集处理逻辑,例如对结果进行加工、过滤、缓存或转换等操作。

3.3、StatementHandler 语句拦截器:

StatementHandler拦截器类型用于拦截MyBatis的SQL语句处理过程。它在SQL语句执行之前拦截并修改SQL语句、设置参数或进行其他操作。你可以通过实现StatementHandler接口来自定义SQL语句处理逻辑,例如动态修改SQL语句、添加分页逻辑、实现缓存等。

3.4、Executor执行拦截器:

拦截执行器的方法,主要负责SQL的执行,包括INSERT、UPDATE、DELETE等操作以及SELECT查询操作。通过拦截Executor接口的方法,可以实现对数据库操作前后的统一处理,比如开启事务、记录日志、分页处理、二级缓存控制等。

4、实际应用

4.1、自定义拦截器
package com.springboot.cli;import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.lang.reflect.Method;
import java.util.Properties;/*** 类说明:@Intercepts注解用于标注一个类是一个MyBatis拦截器;@Signature注解用于指定一个方法的签名,其中包括方法所在的接口、方法名以及方法的参数列表* type参数指定了被拦截的接口类型,比如Executor.class表示要拦截Executor接口的方法。* method参数指定了要拦截的方法名。* args参数是一个Class数组,用来指定方法的参数类型列表,通过这些参数类型可以唯一确定要拦截的方法。* 如果需要拦截多个不同类型的方法,可以在@Intercepts注解中指定多个@Signature注解。** @author liangtl* @Date 2024/7/14*/
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MybatisInterceptor implements Interceptor {private Properties properties;@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 代理对象Object target = invocation.getTarget();// 代理方法Method method = invocation.getMethod();// 方法参数Object[] args = invocation.getArgs();// 如果args长度大于1,说明有附带的其他参数Object parameter = null;if (args.length > 1) {// 查询参数parameter = args[1];}MappedStatement mappedStatement = (MappedStatement) args[0];// sqlIdString sqlId = mappedStatement.getId();// 拼接完成的sqlString sql = mappedStatement.getBoundSql(parameter).getSql();// 这里一定需要使用invocation.proceed()返回,以保证sql继续执行。// 如果想进行判断然后中断sql执行,可以返回emptyList。return invocation.proceed();}/*** 生成MyBatis拦截器代理对象(非必须)*/@Overridepublic Object plugin(Object target) {if(target instanceof StatementHandler){//调用插件return Plugin.wrap(target, this);}return target;}/*** 设置插件属性(直接通过Spring的方式获取属性,所以这个方法一般也用不到)* 项目启动的时候数据就会被加载*/@Overridepublic void setProperties(Properties properties) {//赋值成员变量,在其他方法使用。this.properties = properties;}
}
4.2、注册拦截器

拦截器注册有两种方式,一种是在配置文件中配置,第二种是通过代码的形式。

这里演示使用代码进行拦截器注册。

package com.springboot.cli;import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;/*** 数据源配置Demo** @author liangtl* @Date 2024/7/14*/@Configuration
public class DataSourceConfig {@Value("${test.datasource.url}")private String url;@Value("${test.datasource.username}")private String user;@Value("${test.datasource.password}")private String password;@Value("${test.datasource.driverClassName}")private String driverClass;@Bean(name = "dataSource")public DataSource dataSource() {PooledDataSource dataSource = new PooledDataSource();dataSource.setDriver(driverClass);dataSource.setUrl(url);dataSource.setUsername(user);dataSource.setPassword(password);return dataSource;}@Bean(name = "transactionManager")public DataSourceTransactionManager dataSourceTransactionManager() {return new DataSourceTransactionManager(dataSource());}@Bean(name = "sqlSessionFactory")public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);sessionFactory.setPlugins(new MybatisInterceptor());// 设置mapper文件位置sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:**/**/mapper/*.xml"));// 设置实体类映射规则: 下划线 -> 驼峰org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();configuration.setMapUnderscoreToCamelCase(true);sessionFactory.setConfiguration(configuration);return sessionFactory.getObject();}
}

在我们定义的sqlSessionFactory这个bean中,sessionFactory.setPlugins(new MybatisInterceptor());这一行代码就是我们注册自定义拦截器的地方。

至此,Mybatis拦截器就已经从自定义到注册完成,当我们注入的是sqlSessionFactory这个Factory时,拦截器就会生效。

5、扩展

有些时候我们可能需要在拦截器中注入一些我们需要的类来完成一些特定的逻辑,于是我们默认使用@Autowired去将其注入,结果发生代码执行时报了NPE,因为注入的属性为null。

原因如下:

因为拦截器对象是由Servlet容器负责创建和管理的,而不是由Spring容器管理的。因此,Spring容器无法感知并注入拦截器中的属性。

现在已经知道原因了,那么就可以解决这个问题。

方法一:将拦截器作为一个Spring Bean进行配置,交由Spring容器进行管理

方法二:既然拦截器中无法注入,那就不注入了。新增一个有参构造使用构造器的方式注入属性

方法三:可以通过实现ApplicationContextAware接口或者直接在拦截器中获取ApplicationContext对象,然后从ApplicationContext中获取需要的Bean

参考博客:

Mybatis拦截器_@intercepts-CSDN博客

MyBatis拦截器四种类型和自定义拦截器的使用流程_mybatis 拦截器-CSDN博客

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • ROM修改进阶教程------深度解析小米设备锁机型不解锁bl 刷写特殊类固件的步骤
  • 知识梳理:Postman使用详解
  • 案例 | 人大金仓助力山西政务服务核心业务系统实现全栈国产化升级改造
  • Python爬虫获取王者荣耀英雄全皮肤图片,并下载到本地
  • 在mysql中delete和truncated的相同点和区别点
  • Detrs beat yolos on real-time object detection
  • 大模型笔记3 Longformer for Extractive Summarization训练
  • 351_C++_自定义list容器的sort排序规则sortFileName,函数调用运算符 operator() 的重载,它使得一个对象可以像函数一样被调用
  • 支付通道安全:应对黑客攻击的策略与实践
  • 【SC05B】触摸芯片-高灵敏度、强抗干扰能力和稳定性
  • Matlab 判断直线上一点
  • Vue项目中禁用ESLint的几种常见方法
  • SSLRec代码分析
  • 从概念到完成:Midjourney——设计思维与AI技术的完美结合
  • 桃园南路上的红绿灯c++
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • classpath对获取配置文件的影响
  • codis proxy处理流程
  • crontab执行失败的多种原因
  • css布局,左右固定中间自适应实现
  • IndexedDB
  • input实现文字超出省略号功能
  • Mysql5.6主从复制
  • PHP面试之三:MySQL数据库
  • Redis 懒删除(lazy free)简史
  • Windows Containers 大冒险: 容器网络
  • 码农张的Bug人生 - 初来乍到
  • 排序(1):冒泡排序
  • 收藏好这篇,别再只说“数据劫持”了
  • 小程序开发之路(一)
  • 正则与JS中的正则
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • 正则表达式-基础知识Review
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • $.ajax中的eval及dataType
  • (1)SpringCloud 整合Python
  • (3)nginx 配置(nginx.conf)
  • (3)医疗图像处理:MRI磁共振成像-快速采集--(杨正汉)
  • (Git) gitignore基础使用
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (含笔试题)深度解析数据在内存中的存储
  • (九)信息融合方式简介
  • (面试必看!)锁策略
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (数据结构)顺序表的定义
  • (四)图像的%2线性拉伸
  • (一一四)第九章编程练习
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • .NET BackgroundWorker