Mr. Cappuccino的第56杯咖啡——Mybatis拦截器
Mybatis拦截器
- 概述
- 应用场景
- 项目结构
- 实现分页查询
- 其它拦截器的使用
概述
Mybatis允许使用者在映射语句执行过程中的某一些指定的节点进行拦截调用,通过织入拦截器,在不同节点修改一些执行过程中的关键属性,从而影响SQL的生成、执行和返回结果。
默认情况下,Mybatis支持四种对象拦截:
- Executor:拦截执行器的方法;
- ParameterHandler:拦截参数的处理;
- ResultSetHandler:拦截结果集的处理;
- StatementHandler:拦截Sql语法构建的处理;
执行顺序:Executor => StatementHandler => ParameterHandler => ResultSetHandler
注:本文代码基于《Mybatis一级缓存&二级缓存》中的“一级缓存(Spring整合Mybatis)”的代码进行调整。
应用场景
- 分页查询;
- 数据脱敏;
- 数据过滤;
- 监控Sql语句执行耗时;
项目结构
实现分页查询
StatementInterceptor.java
package com.mybatis.interceptor;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;/*** @author honey* @date 2023-08-02 15:25:26*/
@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
})
@Component
public class StatementInterceptor implements Interceptor {@Value("${mybatis.page-helper.rule}")private String rule;@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();MetaObject metaObject = SystemMetaObject.forObject(statementHandler);MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();// 判断sql语句的类型switch (sqlCommandType) {case SELECT:extendLimit(statementHandler);break;case INSERT:case UPDATE:case DELETE:case FLUSH:default:break;}log.info("【StatementInterceptor】方法拦截前执行");Object result = invocation.proceed();log.info("【StatementInterceptor】方法拦截后执行");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}private void extendLimit(StatementHandler statementHandler) throws NoSuchFieldException, IllegalAccessException {// 获取原生sql语句BoundSql boundSql = statementHandler.getBoundSql();Class<? extends BoundSql> aClass = boundSql.getClass();// 使用反射机制修改原生sql语句Field sql = aClass.getDeclaredField("sql");sql.setAccessible(true);String oldSqlStr = boundSql.getSql();log.info("原生sql语句:{}", oldSqlStr);// 加上分页规则sql.set(boundSql, oldSqlStr + " " + rule);}
}
application.yml
mybatis:page-helper:rule: limit 2
其它拦截器的使用
ExecutorInterceptor.java
package com.mybatis.interceptor;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;import java.util.Properties;/*** @author honey* @date 2023-08-02 18:11:28*/
@Slf4j
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
@Component
public class ExecutorInterceptor implements Interceptor {Properties properties;@Overridepublic Object intercept(Invocation invocation) throws Throwable {log.info("【ExecutorInterceptor】方法拦截前执行");Object result = invocation.proceed();log.info("【ExecutorInterceptor】方法拦截后执行");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {this.properties = properties;}
}
ParameterInterceptor.java
package com.mybatis.interceptor;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;import java.sql.PreparedStatement;
import java.util.Properties;/*** @author honey* @date 2023-08-02 18:22:15*/
@Slf4j
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
})
@Component
public class ParameterInterceptor implements Interceptor {Properties properties;@Overridepublic Object intercept(Invocation invocation) throws Throwable {log.info("【ParameterInterceptor】方法拦截前执行");Object result = invocation.proceed();log.info("【ParameterInterceptor】方法拦截后执行");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {this.properties = properties;}
}
ResultSetInterceptor.java
package com.mybatis.interceptor;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;import java.sql.Statement;
import java.util.Properties;/*** @author honey* @date 2023-08-02 18:24:00*/
@Slf4j
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
@Component
public class ResultSetInterceptor implements Interceptor {Properties properties;@Overridepublic Object intercept(Invocation invocation) throws Throwable {log.info("【ResultSetInterceptor】方法拦截前执行");Object result = invocation.proceed();log.info("【ResultSetInterceptor】方法拦截后执行");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {this.properties = properties;}
}
相关文章:

Mr. Cappuccino的第56杯咖啡——Mybatis拦截器
Mybatis拦截器 概述应用场景项目结构实现分页查询其它拦截器的使用 概述 Mybatis允许使用者在映射语句执行过程中的某一些指定的节点进行拦截调用,通过织入拦截器,在不同节点修改一些执行过程中的关键属性,从而影响SQL的生成、执行和返回结果…...

容器化安装环境EFK搭建
容器化安装环境 Docker中安装并启动ElasticSearch 前置配置 第一步:在宿主机上执行echo “net.ipv4.ip_forward1” >>/usr/lib/sysctl.d/00-system.conf 2.第二步:重启network和docker服务 [rootlocalhost /]# systemctl restart network &&…...

基于 Debian GNU/Linux 12 “书虫 “的Neptune 8.0 “Juna “来了
导读Neptune Linux 发行版背后的团队发布了 Neptune 8.0,作为这个基于 Debian 的 GNU/Linux 发行版的重大更新,它围绕最新的 KDE Plasma 桌面环境构建。 Neptune 8.0 被命名为 “Juna”,是在Neptune 7.5 发布 11 个月后发布的,也是…...
GDAL C++ API 学习之路 (4) Spatial Reference System篇 OGRSpatialReference类
class OGRSpatialReference #include <ogr_spatialref.h> OGRSpatialReference 是 GDAL/OGR 库中的一个重要类,用于管理和操作地理空间数据的空间参考系统(Spatial Reference System,SRS)。它提供了一系列功能&…...

RS232转Profinet网关rs232转网口需要如何设置
大家好,今天我要给大家带来一个很有意思的案例分享。你们猜猜,这回我们要用捷米的一款神奇的网关JM-RS485/232-PN做什么呢?没错,我们要把一台扫码枪设备通过这个RS232转PROFINET网关,接入到一台西门子S7-1200PLC的Prof…...

LaTex的下载与安装超详细windows版
1.LaTex的下载 (texlive下载TexStudio下载) (1)texlive下载: 这里清华镜像下载 (2)TexStudio下载: 点这里下载镜像 可以根据不同的系统选择不同的版本 2 .LaTex的安装 &#…...
MySQL | 存储过程快速入门
文章目录 一、概述1.1 MySQL存储过程和函数的概念1.2 优势和适用场景 二、存储过程基础2.1 存储过程与传统SQL查询的区别2.2 创建和调用存储过程创建存储过程调用存储过程 2.3 参数传递与返回值创建带有输出参数的存储过程调用带有输出参数的存储过程 2.4 流程控制语句IF语句WH…...

C# 图表控件库 ScottPlot
推荐使用ScottPlot原因: 1.图形界面简洁,样式丰富 2.代码较少 3.官方提供多种实例源码,并可以直接通过图形界面查看,便于快速开发 Github源码链接:https://github.com/ScottPlot/ScottPlot 官网WindowFrom Demo实例…...

013 怎么查看自己电脑的wifi密码
方法一:查看当前电脑连接的无线密码 步骤1: 打开windows命令行窗口,输入:ncpa.cpl 快速打开“控制面板”中的“网络连接”,如下图: 步骤2: 右键,打开“状态” 步骤3:…...
深入了解 LoRaWAN® MAC 命令
本文深入探讨了用于 LoRaWAN 网络管理的 MAC 命令。它面向终端设备软件开发人员和使用 LoRa 构建设备的团队经理,这些设备实现了LoRaWAN 链路层规范 v1.0.4。本文帮助您了解不同类型的 MAC 命令、每个命令的用途以及如何解释这些命令。 已经使用LoRaMAC-Node™等软件来处理 MA…...
跨境电商与隐擎fox指纹浏览器:保障安全与效率的完美结合
随着全球化的发展,跨境电商已成为各国贸易的重要组成部分。然而,随之而来的风险和挑战也日益增多,其中之一就是关联浏览器和多开浏览器可能带来的安全隐患。为了确保跨境电商的顺利运营和数据安全,隐擎fox指纹浏览器作为一种防关联…...

【网络编程】五种网络IO模式
对于一次IO访问(以read为例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,会经历两个阶段: 1、等待数据准…...
面试总结-2023版
本文受众主要为,互联网技术研发人员。 技术面试一般三面和HRBP面不太会卡人,主要都是停在了一面和二面上。我这次换工作前期主要是一面通过率比较低,后面主要是二面通过低。 总结影响面试通过的几点因素: 是否真的招人…...

bigemap在草原行业的应用案例
一.为什么选择Bigemap 1.使用软件一般都用于套坐标以及空间规划图,方便于项目选址和居民建房报建 2.在卫星图上找到用地范围,然后打点,导出点位范围的2000坐标,用于汇报出图 3.CGCS2000坐标系通过矢量转换转成地方坐标系...

DevOps系列文章之 java调用python脚本
在java类中直接执行python语句 在java类中直接调用本地python脚本 使用Runtime.getRuntime()执行python脚本文件(推荐) 调用python脚本中的函数 简单介绍 官网地址 首页 | (jython.org) Jython项目提供了Java中的Python实现, 为Python提供了…...
PHP异步框架总结
目前主要有: 国产 swoole workerman 国外 framework-x revoltrevolt reactphp amphp async...
vsto excel 可以异步写入值么
在 VSTO (Visual Studio Tools for Office) 中,Excel 可以使用异步方式写入值。异步编程允许您在后台线程中执行耗时的操作,而不会阻塞主线程,从而提高程序的响应性能。 从 .NET 4.5 开始,可以使用异步和 await 关键字来简化异步…...

Android Gradle 骚操作,将两个项目合并到一个项目中
1. 前言 在工作中,由于各种原因,导致需要将两个可单独运行的App项目,合并到一个git仓库里,且单独的App项目里还有其他Module模块。 如果只是将两个项目复制到同一个文件夹下,还是得单独打开各个项目,是很不…...

虹科案例|如何分析设备故障时间和次数,打破生产瓶颈?
虹科设备绩效管理系统 保障生产设备的稳定性和可靠性 生产设备的稳定性和可靠性是保证企业正常生产的重要条件之一,设备故障的频发严重影响企业的正常生产,那么如何分析设备故障时间和次数,查找设备故障原因,协助企业打破生产瓶…...

SVN代码迁移到Git方法
1.在SVN上新增一个项目 一、点击新建项目 二、创建空白项目 三、填入项目信息 四、myProject项目模板创建成功 2.将代码提交到Git 一、新建一个文件夹myProject,将从SVN下载过来的代码复制一份拷贝到该文件夹下,注意:不要把.SVN文件拷…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...