基于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();}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36178.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36178.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36178.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

創新零售,京東重新答題?

繼新一輪組織架構調整后&#xff0c;京東從低價到下沉動作不斷。 新成立的創新零售部在京東老將閆小兵的帶領下悄然完成了整合。近日&#xff0c;京喜拼拼已改名為京東拼拼&#xff0c;與七鮮、前置倉等業務共同承載起京東線上線下加速融合的夢想。 同時&#xff0c;拼拼的更…

【從零學習python 】19. 循環遍歷列表和列表嵌套的應用

文章目錄 列表的循環遍歷1. 使用while循環2. 使用for循環3. 交換2個變量的值1. 列表嵌套2. 應用 進階案例 列表的循環遍歷 1. 使用while循環 為了更有效率的輸出列表的每個數據&#xff0c;可以使用循環來完成 namesList [xiaoWang,xiaoZhang,xiaoHua] length len(namesLi…

零售行業供應鏈管理核心KPI指標(一) – 能力、速度、效率和成本

有關零售行業供應鏈管理KPI指標的綜合性分享&#xff0c;涉及到供應鏈能力、速度、效率和成本總共九大指標&#xff0c;是一個大框架&#xff0c;比較核心也比較綜合。 衡量消費品零售企業供應鏈管理效率和水平的核心KPI通常有哪些&#xff1f; 圖片來源-派可數據&#xff08;…

C++ unique_ptr概述 常用操作

文章目錄 unique_ptr概述unique_ptr常用操作 unique_ptr概述 uniue_ptr是一個獨占式的指針,同一個時刻, 就只能有一個unique_ptr指向這個對象(內存),unique_ptr的使用格式 unique_ptr<Class_Tyep> P_Name; unique_ptr的常規初始化: unique_ptr<int> p; 創建一個空…

監控Kafka的關鍵指標

Kafka 架構 上面綠色部分 PRODUCER&#xff08;生產者&#xff09;和下面紫色部分 CONSUMER&#xff08;消費者&#xff09;是業務程序&#xff0c;通常由研發人員埋點解決監控問題&#xff0c;如果是 Java 客戶端也會暴露 JMX 指標。組件運維監控層面著重關注藍色部分的 BROKE…

Vue 實現重定向、404和路由鉤子(六)

一、重定向 1.1 修改 Main.vue <template><div><el-container><el-aside width"200px"><el-menu :default-openeds"[1]"><el-submenu index"1"><template slot"title"><i class"…

MongoDB常用命令

什么是MongoDB ? MongoDB 是由C語言編寫的&#xff0c;是一個基于分布式文件存儲的開源數據庫系統。 在高負載的情況下&#xff0c;添加更多的節點&#xff0c;可以保證服務器性能。 MongoDB 旨在為WEB應用提供可擴展的高性能數據存儲解決方案。 MongoDB 將數據存儲為一個…

【網絡基礎實戰之路】基于BGP協議中的聯邦號連接三個AS區域的實戰詳解

系列文章傳送門&#xff1a; 【網絡基礎實戰之路】設計網絡劃分的實戰詳解 【網絡基礎實戰之路】一文弄懂TCP的三次握手與四次斷開 【網絡基礎實戰之路】基于MGRE多點協議的實戰詳解 【網絡基礎實戰之路】基于OSPF協議建立兩個MGRE網絡的實驗詳解 【網絡基礎實戰之路】基于…

Dalsa線陣相機說明(Linea Color GigESeries 2k and 4K)

文章目錄 一. Dalsa相機軟件整體架構二. 相機編號說明以及軟件要求三. 相機硬件參數三. 相機基本參數四. 軟件參數設置列表1. Sensor Control Category2. I/O Control Category3. Counter and Timer Control Category4. Advanced Processing Control Category(1) 平場校正介紹(…

學習Vue:插值表達式和指令

在 Vue.js 中&#xff0c;Vue 實例與數據綁定是構建動態交互界面的關鍵。在這篇文章中&#xff0c;我們將重點介紹 Vue 實例中兩種實現數據綁定的方式&#xff1a;插值表達式和指令。這些機制允許您將數據無縫地渲染到界面上&#xff0c;實現實時的數據更新和展示。 插值表達式…

U盤提示格式化怎么修復?學會這幾個方法!

“不知道大家有沒有遇到過將u盤插入電腦后提示格式化的情況呀&#xff1f;第一次遇到這種情況真的好無助&#xff0c;這是可以修復的嗎&#xff1f;請大家幫幫我&#xff01;” U盤作為一個便捷的存儲工具&#xff0c;幫助我們存儲了很多重要的數據和文件。但在使用的過程中&am…

Dockerfile 使用技巧篇

默認的 docker 鏡像使用 Linux 來當作基礎鏡像 01. 使用 alpine 鏡像&#xff0c;而不是默認的 linux 鏡像 PS: alpine 譯為高山植物&#xff0c;就是很少的資源就能存活的意思。alpine 裁剪了很多不必要的 linux 功能&#xff0c;使得鏡像體積大幅減小了。 比如 FROM node:1…

PHP8定義字符串的方法-PHP8知識詳解

字符串&#xff0c;顧名思義&#xff0c;就是將一堆字符串聯在一起。字符串簡單的定義方法是使用英文單引號&#xff08; &#xff09;或英文雙引號&#xff08;" "&#xff09;包含字符。另外&#xff0c;還可以使用定界符定義字符串。本文還介紹了字符串的連接符。…

TCP的三次握手和四次揮手

文章目錄 三次握手四次揮手TIME_WAITCLOSE_WAIT 使用wireshark觀察 三次握手 握手的最終目的是主機之間建立連接 首先要有兩個預備知識點 三次握手建立連接不一定會成功&#xff0c;其中最擔心的就是最后一次握手失敗&#xff0c;不過會有配套的解決方案建立好連接后是需要被…

【重溫老古董——Strust2框架】基于Idea使用maven創建Strust2項目

1、新建項目 紅色圈出的部分是【強制】,其他部分看個人喜好。 2、修改 pom 文件,管理依賴 <dependency><groupId>org.apache.struts</groupId><artifactId>struts2-core</artifactId><version>2.5.22</version></dependency&g…

微服務中RestTemplate訪問其他服務返回值轉換問題

背景&#xff1a; 接收一個springcloud項目&#xff0c;UI模塊訪問其他服務的接口&#xff0c;返回數據統一都是使用fastjson進行轉換&#xff0c;但是新開發了幾個新模塊之后發現fastjson很多bug&#xff08;各種內存溢出&#xff09;&#xff0c;但是很多地方已經重度依賴fa…

數據結構:力扣OJ題(每日一練)

目錄 題一&#xff1a;環形鏈表 思路一&#xff1a; 題二&#xff1a;復制帶隨機指針的鏈表 思路一&#xff1a; 本人實力有限可能對一些地方解釋的不夠清晰&#xff0c;可以自己嘗試讀代碼&#xff0c;望海涵&#xff01; 題一&#xff1a;環形鏈表 給定一個鏈表的頭節點…

IDEA如何調試Stream API

Stream API現在在實際開發中應用非常廣泛&#xff0c;經常會遇到需要調試Stream API的場景&#xff0c;這篇文章主要講解如何使用IDEA調試Stream Testpublic void test(){Stream.of(10, 20, 30, 40, 50).mapToInt(e->e*10).filter(e->e>200).forEach(System.out::pri…

使用css實現時間線布局(TimeLine)

前言 在使用uni-app開發微信小程序過程中&#xff0c;遇到了時間軸布局&#xff0c;由于每項的內容高度不一致&#xff0c;使用uniapp自帶的擴展組件uni-steps&#xff0c;樣式布局無法對齊豎線&#xff0c;于是自己造輪子&#xff0c;完成特殊的布局。顯示效果如下&#xff1…

linux shell變量

linux shell變量 1、變量命名規則2、只讀變量3、刪除變量 1、變量命名規則 變量名不能加$命名只能使用英文字母、數字和下劃線&#xff0c;首個字母不能以數字開頭中間不能有空格。可以有下劃線不能使用標點符號不能使用bash中的關鍵字 username"tom"引用 $userna…