SQL拦截(二)InnerInterceptor

一、介绍

1、简介

InnerInterceptor 接口是 MyBatis-Plus 提供的一个拦截器接口,用于实现一些常用的 SQL 处理逻辑。

二、API

InnerInterceptor 接口继承自 MyBatis 的 Interceptor 接口,并添加了一些新的方法,用于处理 MyBatis-Plus 的特定功能。

package com.baomidou.mybatisplus.extension.plugins.inner;import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;public interface InnerInterceptor {default boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {return true;}default void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {}default boolean willDoUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {return true;}default void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {}default void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {}default void beforeGetBoundSql(StatementHandler sh) {}default void setProperties(Properties properties) {}
}

willDoQuery: 当执行查询操作时,MyBatis 会调用该方法,判断是否需要执行查询操作。默认返回true,表示继续执行查询操作,如果需要阻止查询操作,则可以在实现该方法时返回false。
beforeQuery: 在执行查询操作之前,MyBatis 会调用该方法。通过实现该方法,可以在查询之前进行一些必要的操作,例如设置数据范围、修改 SQL 等。
willDoUpdate: 当执行更新操作时,MyBatis 会调用该方法,判断是否需要执行更新操作。默认返回true,表示继续执行更新操作,如果需要阻止更新操作,则可以在实现该方法时返回false。
beforeUpdate: 在执行更新操作之前,MyBatis 会调用该方法。通过实现该方法,可以在更新之前进行一些必要的操作,例如设置更新时间、加密数据等。
beforePrepare: 在执行 SQL 之前,MyBatis 会调用该方法。通过实现该方法,可以在 SQL 执行之前进行一些必要的操作,例如设置事务隔离级别、设置查询超时时间等。
beforeGetBoundSql: 在获取 BoundSql 对象之前,MyBatis 会调用该方法。通过实现该方法,可以在获取 BoundSql 对象之前进行一些必要的操作,例如设置参数、修改 SQL 等。
setProperties: 设置拦截器属性。该方法在创建拦截器实例时调用,用于设置拦截器的属性。
pluginExecutor: 在创建 Executor 对象时调用,可以在这里对 Executor 对象进行包装或其他处理。

三、使用方法

1、自定义拦截类
implements Interceptor, InnerInterceptor (1)类头需要有@Intercepts注解;(2)需要重写setProperties方法(方法体为空即可),否则会报错:inherits unrelated defaults for setProperties(Properties) from types org.apache.ibatis.plugin.Interceptor and com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor
2、注册

和spring的拦截器org.springframework.web.servlet.HandlerInterceptor 需要注册一样,mybatis的拦截器也需要注册

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.pluscache.demo.interceptor.SqlExplainInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MybatisPlusConfig {@Autowiredprivate SqlExplainInterceptor sqlExplainInterceptor;@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(sqlExplainInterceptor);//interceptor.addInnerInterceptor(xxx);return interceptor;}
}

四、demo 

1、执行explain打印结果
@Data
public class ExplainResultVo {private String id;private String selectType;private String table;private String partitions;private String type;private String possibleKeys;private String key;private String keyLen;private String ref;private String rows;private String filtered;private String extra;
}
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.pluscache.demo.dto.ExplainResultVo;
import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class, method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class SqlExplainInterceptor implements Interceptor, InnerInterceptor {@Overridepublic void setProperties(Properties properties) {//无需改动}@Overridepublic Object intercept(Invocation invocation) throws Throwable {log.info("进入sql分析");try {Object target = invocation.getTarget();Object[] args = invocation.getArgs();if (target instanceof Executor) {final Executor executor = (Executor) target;Object parameter = args[1];log.info("参数,executor={},parameter={}", executor, parameter);boolean isUpdate = args.length == 2;MappedStatement ms = (MappedStatement) args[0];if (!isUpdate && ms.getSqlCommandType() == SqlCommandType.SELECT){BoundSql boundSql;if (args.length == 4) {boundSql = ms.getBoundSql(parameter);} else {boundSql = (BoundSql) args[5];}String sql = getSql(boundSql, ms);log.info("原来 sql 为 {}", sql);this.handleExplain(executor, sql);return invocation.proceed();}}return invocation.proceed();}catch (Exception e){return invocation.proceed();}}private String getSql(BoundSql boundSql, MappedStatement ms) {String sql = boundSql.getSql();Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (!CollectionUtils.isEmpty(parameterMappings) && parameterObject != null) {for (ParameterMapping parameterMapping : parameterMappings) {if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {MetaObject metaObject = ms.getConfiguration().newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameter(value)));}}}return sql;}public String getParameter(Object parameter) {if (parameter instanceof String) {return "'" + parameter + "'";}return parameter.toString();}private void handleExplain(Executor executor, String sql) throws SQLException {Statement stmt = executor.getTransaction().getConnection().createStatement();stmt.execute("EXPLAIN " + sql + " ;");ResultSet rs = stmt.getResultSet();while (rs.next()) {ExplainResultVo explainResultVo = new ExplainResultVo();explainResultVo.setId(rs.getString("id"));explainResultVo.setSelectType(rs.getString("select_type"));explainResultVo.setTable(rs.getString("table"));explainResultVo.setPartitions(rs.getString("partitions"));explainResultVo.setType(rs.getString("type"));explainResultVo.setPossibleKeys(rs.getString("possible_keys"));explainResultVo.setKey(rs.getString("key"));explainResultVo.setKeyLen(rs.getString("key_len"));explainResultVo.setRef(rs.getString("ref"));String rows = rs.getString("rows");explainResultVo.setRows(rows);explainResultVo.setFiltered(rs.getString("filtered"));explainResultVo.setExtra(rs.getString("Extra"));boolean isSimple = "SIMPLE".equals(rs.getString("select_type"));int rowsInt = 0;if (StringUtils.isNotBlank(rows)) {try {rowsInt = Integer.parseInt(rows);} catch (Exception e) {rowsInt = 0;}}log.info("explain语句: {}", explainResultVo);}}
}

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

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

相关文章

Hive数据库操作语法

数据类型 内部表和外部表 内部表 &#xff08;CREATE TABLE table_name ......&#xff09;未被external关键字修饰的即是内部表&#xff0c; 即普通表。 内部表又称管理表,内部表数据存储的位置由hive.metastore.warehouse.dir参数决定&#xff08;默认&#xff1a;/user/h…

车载通信架构 --- PNC、UB与信号的关系

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…

CLIP-Driven Universal Model for Organ Segmentation and Tumor Detection论文解读和实验复现

背景 医学图像数据集的增长&#xff1a;随着公开的医学图像数据集数量的增加&#xff0c;自动化器官分割和肿瘤检测技术得到了显著发展。数据集的局限性&#xff1a;尽管数据集数量增加&#xff0c;但每个数据集通常规模较小&#xff0c;且存在部分标注问题。这意味着不是所有…

如何使用Varjo直接观看Blender内容

最近&#xff0c;开源的3D建模程序Blender为Varjo提供了出色的OpenXR支持&#xff0c;包括四视图和凹进渲染扩展。但是在Blender中&#xff0c;默认不启用VR场景检查。要开始使用VR场景检查&#xff0c;只需遵循以下步骤&#xff1a; 1. 下载并安装Blender 2.启用Blender VR场景…

Go 语言之搭建通用 Web 项目开发脚手架

Go 语言之搭建通用 Web 项目开发脚手架 MVC 模式 MVC 模式代表 Model-View-Controller&#xff08;模型-视图-控制器&#xff09; 模式。这种模式用于应用程序的分层开发。 Model&#xff08;模型&#xff09; - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑&…

Python爬虫基础-正则表达式!

前言 正则表达式是对字符串的一种逻辑公式&#xff0c;用事先定义好的一些特定字符、及这些特定字符的组合&#xff0c;组成一个“规则的字符串”&#xff0c;此字符串用来表示对字符串的一种“过滤”逻辑。正在在很多开发语言中都存在&#xff0c;而非python独有。对其知识点…

AI之硬件对比:据传英伟达Nvidia2025年将推出RTX 5090-32GB/RTX 5080-24GB、华为2025年推出910C/910D

AI之硬件对比&#xff1a;据传英伟达Nvidia2025年将推出RTX 5090-32GB/RTX 5080-24GB、华为2025年推出910C/910D 目录 Nvidia的显卡 Nvidia的5090/5080/4090/4080&#xff1a;据传传英伟达Nvidia RTX 5090后续推出32GB版且RTX 5080后续或推出24GB版 RTX 5090相较于RTX 4090&…

SRS:构建实时免费视频服务器的全方位指南

SRS&#xff08;Simple Realtime Server&#xff09;是一个开源的、基于MIT协议的实时视频服务器&#xff0c;以其简单、高效而著称。它支持多种流媒体协议&#xff0c;包括RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等&#xff0c;使其成为直播和WebRTC领域的理想…

Day95 Docker

Docker的使用 1、Docker是什么 docker是一个用来管理镜像的容器 容器(container)&#xff1a;可以装东西 镜像( image )&#xff1a;所谓的镜像&#xff0c;你可以认为就是一个虚拟机 虚拟机&#xff1a;用软件代理硬件来模拟整个计算机的这样一套软件就成为 虚拟机 镜像说白了…

Imperva 数据库与安全解决方案

Imperva是网络安全解决方案的专业提供商&#xff0c;能够在云端和本地对业务关键数据和应用程序提供保护。公司成立于 2002 年&#xff0c;拥有稳定的发展和成功历史并于 2014 年实现产值1.64亿美元&#xff0c;公司的3700多位客户及300个合作伙伴分布于全球各地的90多个国家。…

搜维尔科技:【煤矿虚拟仿真】煤矿企业、高校、科研单位-多语言支持、数字孪生、交互式学习体验

品牌&#xff1a;SouVR 发票&#xff1a;支持专票、普票 单位&#xff1a;套 版本号&#xff1a;1.0 包装清单&#xff1a;软件1套 软件形式&#xff1a;U盘、光盘 运行环境&#xff1a;windows 应用对象&#xff1a;煤矿企业、高校、科研单位 系统配置&#xff1a;…

[C++]——哈希(附源码)

目录 ​编辑 ​编辑 一、前言 二、正文 2.1 unorder系列关联式容器 2.1.1 unordered_map 2.1.1.1 unorderer_map的介绍 ①unordered_map的构造 ②unordered_map的容量 ③unordered_map的迭代器 ④unordered_map的元素访问 ⑤unordered_map的查询 ⑥unordered_map的修改操…

Linux:防火墙和selinux对服务的影响

1-1selinux 1-1 SELinux是对程序、文件等权限设置依据的一个内核模块。由于启动网络服务的也是程序&#xff0c;因此刚好也 是能够控制网络服务能否访问系统资源的一道关卡。 1-2 SELinux是通过MAC的方式来控制管理进程&#xff0c;它控制的主体是进程&#xff0c;而目标则是…

qt QProgressBar详解

1、概述 QProgressBar是Qt框架中的一个控件&#xff0c;专门用于显示任务的进度。它提供了一个可视化的进度条&#xff0c;让用户能够直观地了解任务的完成程度。QProgressBar支持水平和垂直两种显示方向&#xff0c;并且可以通过设置最小值和最大值来指定进度条的范围。此外&…

力扣最热一百题——杨辉三角

目录 题目链接&#xff1a;118. 杨辉三角 - 力扣&#xff08;LeetCode&#xff09; 题目描述 示例 提示: 解法一&#xff1a;利用特性构建杨辉三角 1. 结果存储结构&#xff1a; 2. 初始化和循环遍历每一层&#xff1a; 3. 构建每一层&#xff1a; 4. 填充中间的元素&…

解决com.mysql.jdbc.NonRegisteringDriver内存泄漏问题

1. 问题背景 线上出现内存报警&#xff0c;通过dump文件&#xff0c;MAT分析&#xff0c;发现mysql-connector-java 有内存泄漏问题 2.问题分析 然后看大对象列表&#xff0c;NonRegisteringDriver 对象确实占内存比较多&#xff0c;里面村的数据库连接的虚引用占比较多 3.解…

【AIGC】ChatGPT提示词Prompt高效编写技巧:逆向拆解OpenAI官方提示词

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;OpenAI官方提示词的介绍OpenAI官方提示词的结构与组成如何通过分析提示词找到其核心组件 &#x1f4af;OpenAI官方提示词分析案例一&#xff1a;制定教学计划案例二&…

Ubuntu 22 安装 Apache Doris 3.0.3 笔记

Ubuntu 22 安装 Apache Doris 3.0.3 笔记 1. 环境准备 Doris 需要 Java 17 作为运行环境&#xff0c;所以首先需要安装 Java 17。 sudo apt-get install openjdk-17-jdk -y sudo update-alternatives --config java在安装 Java 17 后&#xff0c;可以通过 sudo update-alter…

多线程生产消费者模型

线程同步 互斥锁(互斥量)条件变量生产/消费者模型 一、互斥锁 C11提供了四种互斥锁&#xff1a; mutex&#xff1a;互斥锁。timed_mutex&#xff1a;带超时机制的互斥锁。recursive_mutex&#xff1a;递归互斥锁。recursive_timed_mutex&#xff1a;带超时机制的递归互斥锁…

理解 WordPress | 第五篇:页面构建器选择指南

WordPress 专题致力于从 0 到 1 搞懂、用熟这种可视化建站工具。 第一阶段主要是理解。 第二阶段开始实践个人博客、企业官网、独立站的建设。 如果感兴趣&#xff0c;点个关注吧&#xff0c;防止迷路。 什么是 WordPress 构建器 WordPress 构建器&#xff08;Page Builder&am…