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

基于Mybatis Plus的SQL输出拦截器。完美的输出打印 SQL 及执行时长、statement

我们需要想办法打印出完成的SQL,Mybatis为我们提供了 org.apache.ibatis.plugin.Interceptor接口,我们来实现该接口做一些打印SQL的工作

package org.springjmis.core.mp.plugins;import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.SystemClock;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.springjmis.core.tool.utils.StringUtil;import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Statement;
import java.util.*;/*** 用于输出每条 SQL 语句及其执行时间** @author hubin nieqiurong TaoYu* @since 2016-07-07*/
@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),@Signature(type = StatementHandler.class, method = "update", args = Statement.class),@Signature(type = StatementHandler.class, method = "batch", args = Statement.class)
})
public class SqlLogInterceptor implements Interceptor {private static final String DRUID_POOLED_PREPARED_STATEMENT = "com.alibaba.druid.pool.DruidPooledPreparedStatement";private static final String T4C_PREPARED_STATEMENT = "oracle.jdbc.driver.T4CPreparedStatement";private static final String ORACLE_PREPARED_STATEMENT_WRAPPER = "oracle.jdbc.driver.OraclePreparedStatementWrapper";private Method oracleGetOriginalSqlMethod;private Method druidGetSqlMethod;@Overridepublic Object intercept(Invocation invocation) throws Throwable {Statement statement;Object firstArg = invocation.getArgs()[0];if (Proxy.isProxyClass(firstArg.getClass())) {statement = (Statement) SystemMetaObject.forObject(firstArg).getValue("h.statement");} else {statement = (Statement) firstArg;}MetaObject stmtMetaObj = SystemMetaObject.forObject(statement);try {statement = (Statement) stmtMetaObj.getValue("stmt.statement");} catch (Exception e) {// do nothing}if (stmtMetaObj.hasGetter("delegate")) {//Hikaritry {statement = (Statement) stmtMetaObj.getValue("delegate");} catch (Exception ignored) {}}String originalSql = null;String stmtClassName = statement.getClass().getName();if (DRUID_POOLED_PREPARED_STATEMENT.equals(stmtClassName)) {try {if (druidGetSqlMethod == null) {Class<?> clazz = Class.forName(DRUID_POOLED_PREPARED_STATEMENT);druidGetSqlMethod = clazz.getMethod("getSql");}Object stmtSql = druidGetSqlMethod.invoke(statement);if (stmtSql instanceof String) {originalSql = (String) stmtSql;}} catch (Exception e) {e.printStackTrace();}} else if (T4C_PREPARED_STATEMENT.equals(stmtClassName)|| ORACLE_PREPARED_STATEMENT_WRAPPER.equals(stmtClassName)) {try {if (oracleGetOriginalSqlMethod != null) {Object stmtSql = oracleGetOriginalSqlMethod.invoke(statement);if (stmtSql instanceof String) {originalSql = (String) stmtSql;}} else {Class<?> clazz = Class.forName(stmtClassName);oracleGetOriginalSqlMethod = getMethodRegular(clazz, "getOriginalSql");if (oracleGetOriginalSqlMethod != null) {//OraclePreparedStatementWrapper is not a public class, need set this.oracleGetOriginalSqlMethod.setAccessible(true);if (null != oracleGetOriginalSqlMethod) {Object stmtSql = oracleGetOriginalSqlMethod.invoke(statement);if (stmtSql instanceof String) {originalSql = (String) stmtSql;}}}}} catch (Exception e) {//ignore}}if (originalSql == null) {originalSql = statement.toString();}originalSql = originalSql.replaceAll("[\\s]+", StringPool.SPACE);int index = indexOfSqlStart(originalSql);if (index > 0) {originalSql = originalSql.substring(index);}// 计算执行 SQL 耗时long start = SystemClock.now();Object result = invocation.proceed();long timing = SystemClock.now() - start;// SQL 打印执行结果Object target = PluginUtils.realTarget(invocation.getTarget());MetaObject metaObject = SystemMetaObject.forObject(target);MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");// 打印 sqlSystem.err.println(StringUtil.format("\n==============  Sql Start  ==============" +"\nExecute ID  :{}" +"\nExecute SQL :{}" +"\nExecute Time:{} ms" +"\n==============  Sql  End   ==============\n",ms.getId(), originalSql, timing));return result;}@Overridepublic Object plugin(Object target) {if (target instanceof StatementHandler) {return Plugin.wrap(target, this);}return target;}/*** 获取此方法名的具体 Method** @param clazz      class 对象* @param methodName 方法名* @return 方法*/private Method getMethodRegular(Class<?> clazz, String methodName) {if (Object.class.equals(clazz)) {return null;}for (Method method : clazz.getDeclaredMethods()) {if (method.getName().equals(methodName)) {return method;}}return getMethodRegular(clazz.getSuperclass(), methodName);}/*** 获取sql语句开头部分** @param sql ignore* @return ignore*/private int indexOfSqlStart(String sql) {String upperCaseSql = sql.toUpperCase();Set<Integer> set = new HashSet<>();set.add(upperCaseSql.indexOf("SELECT "));set.add(upperCaseSql.indexOf("UPDATE "));set.add(upperCaseSql.indexOf("INSERT "));set.add(upperCaseSql.indexOf("DELETE "));set.remove(-1);if (CollectionUtils.isEmpty(set)) {return -1;}List<Integer> list = new ArrayList<>(set);list.sort(Comparator.naturalOrder());return list.get(0);}}

在MybatisPlusConfiguration拦截


package org.springjmis.core.boot.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import lombok.AllArgsConstructor;
import org.mybatis.spring.annotation.MapperScan;
import org.springjmis.core.boot.props.MybatisPlusProperties;
import org.springjmis.core.mp.plugins.SqlLogInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** mybatisplus 配置** @author Chill*/
@Configuration(proxyBeanMethods = false)
@AllArgsConstructor
@MapperScan("org.springjmis.**.mapper.**")
@EnableConfigurationProperties(MybatisPlusProperties.class)
public class MybatisPlusConfiguration {/*** mybatis-plus 拦截器集合*/@Bean@ConditionalOnMissingBean(MybatisPlusInterceptor.class)public MybatisPlusInterceptor mybatisPlusInterceptor(MybatisPlusProperties mybatisPlusProperties) {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 配置分页拦截器PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();paginationInnerInterceptor.setMaxLimit(mybatisPlusProperties.getPageLimit());paginationInnerInterceptor.setOverflow(mybatisPlusProperties.getOverflow());interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;}/*** sql 日志** @return SqlLogInterceptor*/@Bean@ConditionalOnProperty(value = "blade.mybatis-plus.sql-log", matchIfMissing = true)public SqlLogInterceptor sqlLogInterceptor() {return new SqlLogInterceptor();}}

相关文章:

基于Mybatis Plus的SQL输出拦截器。完美的输出打印 SQL 及执行时长、statement

我们需要想办法打印出完成的SQL&#xff0c;Mybatis为我们提供了 org.apache.ibatis.plugin.Interceptor接口&#xff0c;我们来实现该接口做一些打印SQL的工作 package org.springjmis.core.mp.plugins;import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; impor…...

C++ STL list

✅<1>主页&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;C之 STL list介绍和模拟实现 ☂️<3>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<4>前言&#xff1a;上次我们详细的介绍了vector&#xff0c;今天我们继续来介绍…...

Django图书商城系统实战开发-实现订单管理

Django图书商城系统实战开发-实现订单管理 简介 在本教程中&#xff0c;我们将继续基于Django框架开发图书商城系统&#xff0c;这次的重点是实现订单管理功能。订单管理是一个电子商务系统中非常重要的部分&#xff0c;它涉及到用户下单、支付、发货以及订单状态的管理等方面…...

POJ 3421 X-factor Chains 埃氏筛法+质因子分解+DFS

一、思路 我们先用埃氏筛法&#xff0c;找出1048576范围内的素数&#xff0c;其实找出1024以内的就够了&#xff0c;但是1048576也不大&#xff0c;所以无所谓了。 然后把输入的数字不断的判断与每个素数是否整除&#xff0c;然后把输入的数变为很多个素数相乘的形式&#xf…...

【积水成渊】9 个CSS 伪元素

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…...

【002】学习笔记之typescript的【任意类型】

任意类型 顶级类型&#xff1a;any类型和 unknown 类型 any类型 声明变量的时候没有指定任意类型默认为any任意类型都可以赋值给any&#xff0c;不需要检查类型。也是他的弊端如果使用any 就失去了TS类型检测的作用 unknown 类型 TypeScript 3.0中引入的 unknown 类型也被认为…...

题目:2574.左右元素和的差值

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;2574. 左右元素和的差值 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 按题目要求模拟即可。 解题代码&#xff1a; class Solution {public int[] leftRightDifference(int[] nums) {i…...

成集云 | 用友U8采购请购单同步钉钉 | 解决方案

源系统成集云目标系统 方案介绍 用友U8是中国用友集团开发和推出的一款企业级管理软件产品。具有丰富的功能模块&#xff0c;包括财务管理、采购管理、销售管理、库存管理、生产管理、人力资源管理、客户关系管理等&#xff0c;可根据企业的需求选择相应的模块进行集…...

爬虫的代理IP池写哪里了?

亲爱的程序员小伙伴们&#xff0c;想要提高爬虫效率和稳定性&#xff0c;组建一个强大的代理IP池是非常重要的一步&#xff01;今天我就来和你分享一下&#xff0c;代理IP池到底应该写在哪里&#xff0c;以及如何打造一个令人瞩目的代理IP池&#xff01;准备好了吗&#xff1f;…...

CSS变形与动画(三):animation帧动画详解(用法 + 四个例子)

文章目录 animation 帧动画使用定义例子1 字母例子2 水滴例子3 会动的边框例子4 旋转木马 animation 帧动画 定义好后作用于需要变化的标签上。 使用 animation-name 设置动画名称 animation-duration: 设置动画的持续时间 animation-timing-function 设置动画渐变速度 anim…...

Ubuntu发布java版本

1、连接服务器 2、进入目录 cd /usr/safety/app/3、上传jar文件 4、杀掉原java进程 1. 查看当前java进程 2. ps -ef|grep java 3. ycmachine:/usr/safety/app$ ps -ef|grep java root 430007 1 6 01:11 pts/0 00:02:45 /usr/local/java/jdk1.8.0_341/bin/j…...

Java反射机制是什么?

Java反射机制是 Java 语言的一个重要特性。 在学习 Java 反射机制前&#xff0c;大家应该先了解两个概念&#xff0c;编译期和运行期。 编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些…...

legacy-peer-deps的作用

加入ui组件库&#xff0c;以element-ui为例子 安装命令&#xff1a; npm i element-ui -S 如果安装不上&#xff0c;是因为npm版本问题报错&#xff0c;那么就使用以下命令 npm i element-ui -S --legacy-peer-deps那么legacy-peer-deps的作用是&#xff1f; 它是用于绕过pee…...

卷积操作后特征图尺寸,感受野,参数量的计算

文章目录 1、输出特征图的尺寸大小2、感受野的计算3、卷积核的参数量 1、输出特征图的尺寸大小 如果包含空洞卷积&#xff0c;即扩张率dilation rate不为1时&#xff1a; 2、感受野的计算 例如&#xff0c;图像经过两个3*3&#xff0c;步长为2的卷积后感受野为&#xff1a; co…...

C/C++ 注意点补充

C/C 注意点补充 地址与指针函数缺省 地址与指针 p的值是a的地址值&#xff0c;p的类型是int*&#xff0c;p的值是十六进制表示的地址值 所以可以直接把地址值通过强制转换 转换为地址p 如上图&#xff01;&#xff01;&#xff01; int a10; int *p&a; printf("%#p\n&…...

Python实时监控键盘的输入并打印出来

要实现Python实时监控键盘的输入并打印出来&#xff0c;可以使用pynput模块。 首先&#xff0c;需要安装pynput模块&#xff1a; pip install pynput 然后&#xff0c;可以编写以下代码来实现实时监控键盘输入并打印出来的功能&#xff1a; from pynput import keyboard# 定…...

LaWGPT零基础部署win10+anaconda

准备代码&#xff0c;创建环境 # 下载代码 git clone https://github.com/pengxiao-song/LaWGPT cd LaWGPT # 创建环境 conda create -n lawgpt python3.10 -y conda activate lawgpt pip install -r requirements.txt # 启动可视化脚本&#xff08;自动下载预训练模型约15GB…...

糖尿病视网膜病变,黄斑病变,年龄相关检测研究(Matlab代码)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

管理类联考——逻辑——真题篇——按知识分类——汇总篇——一、形式逻辑——选言——相容选言——或——第一节 推结论

第五章 选言命题:相容选言-或;不相容选言-要么要么 第一节 相容选言-或-推结论-A或B为真,则非A→B,非B→A(否一则肯一) 真题(2010-28)-相容选言-或-推结论-(1)A或B为真,A为假:得B为真(否一则肯一); 28.域控制器储存了域内的账户、密码和属于这个城市的计算机三…...

MySQL数据库——图形化界面工具(DataGrip),SQL(2)-DML(插入、修改和删除数据)

目录 图形化界面工具&#xff08;DataGrip&#xff09; 下载及安装 启动及连接 使用 创建数据库 创建表结构 编写SQL DML 插入 更新和删除 1.修改数据 2.删除数据 总结 图形化界面工具&#xff08;DataGrip&#xff09; 下载及安装 DataGrip下载链接&#xff1a;…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...