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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/45407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pycharm与Gitlab交互

环境准备 1、下载配置好本地Git 2、配置Pycharm上的Git 3、gitlab账号 Gitlab配置 Gitlab配置中文 账号》设置》偏好设置》简体中文 创建项目 命令行操作 打开项目会展示以下步骤 在pycharm克隆gitlab的项目 通过菜单栏 1、在PyCharm的顶部菜单栏中,选择“V…

本地部署,Flash Diffusion: 加速条件扩散模型实现快速图像生成

目录 引言 技术背景 Flash Diffusion 的架构与原理 Flash Diffusion 的主要特点 本地部署 运行结果 实验结果与分析 应用实例 结论 GitHub - gojasper/flash-diffusion: Official implementation of ⚡ Flash Diffusion ⚡: Accelerating Any Conditional Diffusion M…

Linux系统搭建轻量级个人博客VanBlog并一键发布公网远程访问

文章目录 前言1. Linux本地部署2. VanBlog简单使用3. 安装内网穿透4. 创建公网地址5. 创建固定公网地址 前言 今天和大家分享如何在Linux Ubuntu系统搭建一款轻量级个人博客VanBlog,并结合cpolar内网穿透软件生成公网地址,轻松实现随时随地远程访问本地…

相交链表+判断环型链表+求环型链表的入口节点

链表OJ题 一.相交链表二.判断环型链表三.求环型链表的入口节点 一.相交链表 相交链表 相交:两个链表从头开始遍历,尾节点一定是同一个节点。 情况一:当两个链表长度相同时: 情况二:当两个链表长度不同时&#xff1…

考研党暑假回家还是留校,暑假回家就一定完蛋吗?

考研我建议最好还是留校,因为环境比较好! 并不是说回家复习就一定不好,回家要面临三大“敌人”: 1、我们本身的惰性,这个无需多言,在自己熟悉的环境,自己一个人,手机电脑网络零食俱…

python条件

条件语句 if语句 if...else语句 if...elif...else语句 嵌套 is is 是一个身份运算符,用于比较两个对象的身份,即它们在内存中的地址是否相同。这与比较两个对象是否相等的 运算符不同。 运算符比较的是两个对象的值是否相等。 比较对象 比较基本数据…

【Unity】RPG2D龙城纷争(十一)战斗系统之回合制驱动

更新日期:2024年7月11日。 项目源码:第五章发布(正式开始游戏逻辑的章节) 索引 简介一、开始关卡二、进入指定回合三、玩家结束当前回合四、进入下一回合五、通关条件六、检测关卡状态简介 通过前两篇的工作,我们的角色已经能够进行移动、战斗了,此刻,便进入第三个板块…

React基础学习-Day04

React基础学习-Day04 常见的钩子函数及基础使用方式 1.useState useState 是 React 的一个 Hook,用于在函数组件中添加状态。它返回一个状态变量和一个更新该状态的函数。与类组件的 this.state 和 this.setState 相对应,useState 让函数组件也能拥有…

存储实验:Linux挂载iscsi硬盘与华为OceanStor创建LUN全流程

目录 目的环境规划实验实验流程Centos配置0. 关闭防火墙1. 设置网卡信息2. 配置路由3. iscsiadm连接存储 iSCSI LUN创建(以华为OceanStor为例)验证1. 验证是否成功2. 开启自动挂载 目的 实现Linux连接iscsi硬盘,同时实现开机自启挂载 环境规…

掌握本地仓储:Gradle本地仓库配置全指南

掌握本地仓储:Gradle本地仓库配置全指南 在构建自动化的领域中,Gradle以其灵活性和强大的依赖管理功能脱颖而出。管理项目依赖时,经常需要配置本地仓库以优化构建速度、控制依赖版本或支持离线构建。本文将深入探讨如何在Gradle中配置本地仓…

JAVA----泛型

泛型 认识泛型 定义类、接口、方法时,同时声明了一个或者多个类型变量(如:) ,称为泛型类、泛型接口,泛型方法、它们统称为泛型。 作用:利用泛型,可以限制集合存储数据的类型. 泛型…

Gitee简易使用流程(后期优化)

目录 1.修改用户名 2.文件管理 新建文件/文件夹流程如下: 上传文件流程如下: 以主页界面为起点 1.修改用户名 点解右上角的头像--> 点击“账号设置” 点击左边栏里的“个人资料“ 直接修改用户名即可 2.文件管理 选择一个有修改权限仓库&#…

【从0到1进阶Redis】主从复制

笔记内容来自B站博主《遇见狂神说》:Redis视频链接 1、概念 主从复制,是指将一个台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称为主节点(master/leader),后者称为从节点(slave/foll…

this指向解析

先看题目: 第一题: var name window var person1 { name: person1, show1: function () { console.log(this.name) }, show2: () > console.log(th show3: function () { return function () { …

MFC之对话框--重绘元文件

文章目录 实现示例展示需要绘制的窗口/位置控件位置更新下一次示例粗细滑动部分更新 重绘元文件(窗口变化内容消失)方法一:使用元文件方法二:兼容设备方法三:使用自定义类存储绘图数据除画笔外功能处理画笔功能处理 保…

springmvc1

以前的servlet程序: springmvc 不同的处理器:不同的方法或者处理类 所有的请求都会经过dispathcherservlet的doservice方法: mvc原理: 前端控制器:jsp或者什么东西

Python字符串基础与高级操作

在Python中,字符串是不可变的数据类型,用于存储一系列的字符。它们可以被创建、访问、操作和格式化,但一旦创建,其内容就不能改变。下面是一篇关于Python字符串技术的详细讲解,包括创建、访问、更新、转义、运算符、格…

Phpstudy 2018 之xhcms搭建

1、由于直接访问根目录无法进入网站 2、所以采用搭建网站,第一使用系统服务模式、选择php-5.4.45Apache模式 3、网站域名为本地ip地址或者127.0.0.1、端口8085 4、在navicat创建名字为xjcms的数据库,并导入sql数据库文件 5、浏览器输入127.0.0.1:8085直接…

中风伤寒、感冒、六经辨证笔记

目录 基础传经的原因传经的过程及速度传经的危害感冒时体痛头痛的原因根据头痛的位置辨经 太阳病太阳中风外风内热 表虚感冒颗粒(桂枝葛根汤) 少阳病辨病总结伤寒论原文半表半里太阳为开,阳明为阖,少阳为枢胆的作用帮助肠胃消化、…

deepstream读取mp4文件及不同类型视频输入bug解决

在deepstream中使用mp4文件,与rtsp类似,使用uridecodebin即可,(可见官方test.py文件) def create_source_bin(index, uri):print("Creating source bin")# Create a source GstBin to abstract this bins c…