当前位置: 首页 > 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;…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...