手寫MyBatis第58彈:如何優雅輸出可執行的SQL語句--深入理解MyBatis日志機制:

🥂(?′?`?)您的點贊👍?評論📝?收藏?是作者創作的最大動力🤞

💖📕🎉🔥 支持我:點贊👍+收藏??+留言📝歡迎留言討論

🔥🔥🔥(源碼 + 調試運行 + 問題答疑)🔥🔥🔥 ?有興趣可以聯系我

🔥🔥🔥 ?文末有往期免費源碼,直接領取獲取(無刪減,無套路)

MyBatis SQL日志輸出全解析:從基礎實現到高級優化

熱門標題推薦

  1. MyBatis SQL日志輸出深度剖析:從基礎實現到插件優化

  2. 手把手實現MyBatis SQL日志功能:原理、實現與陷阱規避

  3. MyBatis SQL監控終極指南:掌握SQL執行的每一個細節

  4. 深入理解MyBatis日志機制:如何優雅輸出可執行的SQL語句

  5. MyBatis SQL日志輸出全攻略:從簡單打印到高級定制

正文

SQL日志輸出是MyBatis開發中最常用且重要的功能之一,它幫助開發者監控和調試數據庫操作。一個良好的SQL日志系統不僅能顯示執行的SQL語句,還能展示參數值、執行時間等關鍵信息。本文將深入探討MyBatis中SQL日志輸出的實現原理、各種實現方式及其優缺點。

一、SQL日志輸出的重要性

在開發過程中,SQL日志輸出具有不可替代的價值:

  1. 調試與排錯:當SQL執行出現問題時,日志可以幫助快速定位問題

  2. 性能監控:通過記錄SQL執行時間,識別性能瓶頸

  3. 審計追蹤:記錄所有數據庫操作,滿足審計需求

  4. SQL優化:分析實際執行的SQL,進行優化調整

二、基礎SQL日志輸出實現

最簡單的SQL日志輸出可以在StatementHandler.prepare方法之后或Executor執行SQL之前實現:

public class SimpleStatementHandler implements StatementHandler {@Overridepublic Statement prepare(Connection connection) throws SQLException {// 原始prepare邏輯Statement statement = connection.createStatement();// 輸出SQL日志String sql = boundSql.getSql();System.out.println("Executing SQL: " + sql);return statement;}}

這種方式雖然簡單,但只能輸出帶有占位符(?)的SQL,無法顯示實際的參數值。

三、帶參數值的SQL日志輸出

要輸出完整的可執行SQL,需要獲取參數值并替換到SQL中的占位符:

public class ParameterAwareStatementHandler implements StatementHandler {@Overridepublic int update(Statement statement) throws SQLException {// 獲取SQL和參數String sql = boundSql.getSql();Object parameter = boundSql.getParameterObject();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();// 構建完整SQLString completeSql = buildCompleteSql(sql, parameter, parameterMappings);System.out.println("Executing SQL: " + completeSql);// 執行原始邏輯return statement.executeUpdate(sql);}private String buildCompleteSql(String sql, Object parameter, List<ParameterMapping> parameterMappings) {if (parameterMappings == null || parameterMappings.isEmpty()) {return sql;}String completeSql = sql;for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping mapping = parameterMappings.get(i);Object value = getParameterValue(parameter, mapping);completeSql = completeSql.replaceFirst("\\?", formatParameterValue(value));}return completeSql;}}

注意:這種方法僅用于日志輸出,不能直接執行拼接后的SQL,因為存在SQL注入風險。

四、SQL注入風險與安全處理

在拼接SQL參數時,必須注意安全性問題:

  1. 字符串值需要引號包裹:字符串參數必須用單引號包裹

  2. 特殊字符轉義:包含單引號的字符串需要轉義處理

  3. NULL值處理:NULL值應該直接替換為NULL關鍵字

  4. 日期格式處理:日期類型需要轉換為合適的字符串格式

?private String formatParameterValue(Object value) {if (value == null) {return "NULL";}if (value instanceof String) {return "'" + ((String) value).replace("'", "''") + "'";}if (value instanceof Date) {return "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) value) + "'";}if (value instanceof Number) {return value.toString();}return "'" + value.toString().replace("'", "''") + "'";}

五、基于插件的優雅實現

使用MyBatis插件機制可以實現更優雅、非侵入式的SQL日志輸出:

1. 定義日志插件
?@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})public class SqlLogPlugin implements Interceptor {private static final Logger logger = LoggerFactory.getLogger(SqlLogPlugin.class);@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];Object parameter = invocation.getArgs()[1];BoundSql boundSql = mappedStatement.getBoundSql(parameter);String sql = boundSql.getSql();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();// 構建完整SQLString completeSql = buildCompleteSql(sql, parameter, parameterMappings);long start = System.currentTimeMillis();Object result = invocation.proceed();long end = System.currentTimeMillis();logger.info("SQL: {} | Time: {}ms", completeSql, (end - start));return result;}}
2. 配置插件

在MyBatis配置文件中注冊插件:

?<plugins><plugin interceptor="com.example.SqlLogPlugin"><property name="logLevel" value="DEBUG"/></plugin></plugins>

六、高級SQL日志功能

除了基本的SQL輸出,還可以實現更高級的日志功能:

1. 執行時間監控
?public class PerformanceMonitorPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {long start = System.currentTimeMillis();Object result = invocation.proceed();long end = System.currentTimeMillis();long threshold = 1000; // 1秒閾值if (end - start > threshold) {logger.warn("Slow SQL detected: {}ms", (end - start));}return result;}}
2. SQL格式化輸出

對于復雜的SQL,格式化輸出更易于閱讀:

?private String formatSql(String sql) {// 簡單的SQL格式化邏輯sql = sql.replaceAll("(?i)select", "\nSELECT ").replaceAll("(?i)from", "\nFROM ").replaceAll("(?i)where", "\nWHERE ").replaceAll("(?i)join", "\nJOIN ").replaceAll("(?i)order by", "\nORDER BY ").replaceAll("(?i)group by", "\nGROUP BY ");return sql;}
3. 敏感數據脫敏

對于包含敏感信息的SQL,需要進行脫敏處理:

?private String maskSensitiveData(String sql) {// 脫敏手機號sql = sql.replaceAll("1[3-9]\\d{9}", "1**********");// 脫敏身份證號sql = sql.replaceAll("\\d{17}[\\dXx]", "***************");// 脫敏銀行卡號sql = sql.replaceAll("\\d{16,19}", "*******************");return sql;}

七、集成日志框架

直接使用System.out.println不是生產環境的最佳選擇,應該集成成熟的日志框架:

1. SLF4J集成
public class Slf4jSqlLogger {private static final Logger logger = LoggerFactory.getLogger("SQL_LOGGER");public void logSql(String sql, long executionTime, Object... params) {if (logger.isDebugEnabled()) {StringBuilder logMessage = new StringBuilder();logMessage.append("SQL: ").append(sql);logMessage.append(" | Parameters: ").append(Arrays.toString(params));logMessage.append(" | Time: ").append(executionTime).append("ms");logger.debug(logMessage.toString());}}
}
2. 動態日志級別控制

通過配置動態控制SQL日志的詳細程度:

?public enum SqlLogLevel {NONE, ? ?// 不輸出日志BASIC, ? // 只輸出SQL語句PARAMS, ?// 輸出SQL和參數PERFORMANCE, // 輸出SQL、參數和執行時間FULL ? ? // 輸出所有信息}

八、生產環境最佳實踐

在生產環境中使用SQL日志時,應注意以下最佳實踐:

  1. 性能影響:日志輸出可能影響性能,應在必要時開啟

  2. 日志級別控制:根據環境動態調整日志級別

  3. 敏感信息保護:對敏感數據進行脫敏處理

  4. 日志輪轉:配置適當的日志輪轉策略,避免日志文件過大

  5. 監控告警:對慢SQL和異常SQL設置監控告警

九、常見問題與解決方案

1. 日志輸出不完整

問題:參數過多時日志輸出被截斷?解決方案:限制參數輸出長度,或提供摘要信息

2. 性能開銷過大

問題:日志輸出導致性能顯著下降?解決方案:使用異步日志輸出,或采樣輸出部分SQL

3. 特殊類型處理

問題:Blob、Clob等特殊類型無法正常輸出?解決方案:對這些類型提供特殊處理,輸出摘要信息而非完整內容

十、總結

SQL日志輸出是MyBatis開發中不可或缺的功能,從最簡單的System.out.println到基于插件的完整解決方案,每種方式都有其適用場景。在實際項目中,應根據具體需求選擇合適的實現方式,并注意安全性、性能和可維護性等方面的考慮。

通過本文的介紹,相信您已經對MyBatis SQL日志輸出有了全面的了解,能夠根據項目需求實現適合的SQL日志功能,從而更好地監控和優化數據庫操作。


往期免費源碼 (無刪減,無套路):🔥🔥🔥 ?

https://pan.baidu.com/s/1sjAr08PU9Xe7MQf1gjGM5w?pwd=6666?

「在線考試系統源碼(含搭建教程)」 (無刪減,無套路):🔥🔥🔥 ?

鏈接:https://pan.quark.cn/s/96c4f00fdb43 提取碼:WR6M
往期免費源碼對應視頻:

免費獲取--SpringBoot+Vue寵物商城網站系統

🥂(?′?`?)您的點贊👍?評論📝?收藏?是作者創作的最大動力🤞

💖📕🎉🔥 支持我:點贊👍+收藏??+留言📝歡迎留言討論

🔥🔥🔥(源碼 + 調試運行 + 問題答疑)

🔥🔥🔥 ?有興趣可以聯系我

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

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

相關文章

Spring Boot 監控實戰:集成 Prometheus 與 Grafana,打造全方位監控體系

前言 在當今微服務架構盛行的時代&#xff0c;應用程序的監控變得尤為重要。Spring Boot 作為廣泛使用的微服務框架&#xff0c;其監控需求也日益增加。Prometheus 和 Grafana 作為開源監控領域的佼佼者&#xff0c;為 Spring Boot 應用提供了強大的監控能力。本文將詳細介紹如…

JS中的多線程——Web Worker

眾所周知&#xff0c;JavaScript 是單線程運行的&#xff08;至于為什么是單線程可以看一下這篇文章——事件循環機制&#xff09;&#xff0c;當瀏覽器主線程被大量計算任務阻塞時&#xff0c;頁面就會出現明顯的卡頓現象。Web Worker 提供了在獨立線程中運行 JavaScript 的能…

【SQL注入】延時盲注

sleep(n)??: 核心延時函數。使數據庫程序暫停 n秒。??if(condition, true_expr, false_expr)??: 條件判斷函數。如果 condition為真&#xff0c;執行 true_expr&#xff0c;否則執行 false_expr。??用于將延時與判斷條件綁定??。??mid(a, b, c)??: 字符串截取函數…

IntelliJ IDEA 2025.1 Java Stream Debugger 快速使用指南

1. 功能概覽 Java Stream Debugger 提供 Trace Current Stream Chain 功能&#xff0c;用來在調試時分析和可視化 Stream 操作鏈。 主要用途&#xff1a; 在運行時查看流操作鏈的每一步輸出找出 map/filter 等操作的問題避免手動加 peek() 打印調試2. 使用入口 在 IDEA 2025.1 …

ARM-指令集全解析:從基礎到高階應用

一、ARM 指令集體系結構版本ARM 公司定義了多個指令集版本&#xff1a;ARMv1&#xff1a;原型機 ARM1&#xff0c;沒有用于商業產品。ARMv2&#xff1a;擴展 V1&#xff0c;包含 32 位乘法指令和協處理器指令。ARMv3&#xff1a;第一個微處理器 ARM6 核心&#xff0c;支持 Cach…

第3講 機器學習入門指南

近年來&#xff0c;隨著企業和個人生成的數據量呈指數級增長&#xff0c;機器學習已成為日益重要的技術領域。從自動駕駛汽車到流媒體平臺的個性化推薦&#xff0c;機器學習算法已廣泛應用于各個場景。讓我們深入解析機器學習的核心要義。3.1 機器學習定義機器學習是人工智能的…

深入理解跳表:多層索引加速查找的經典實現

跳表&#xff08;Skip List&#xff09;是一種多層有序鏈表結構&#xff0c;通過引入多級索引加速查找&#xff0c;其核心設計類似于“立體高速公路系統”&#xff0c;底層是原始鏈表&#xff0c;上面有各種高度的"高架橋"。 高層道路跨度大&#xff0c;連接遠方節點…

Flutter 視頻播放器——flick_video_player 介紹與使用

在移動端應用中&#xff0c;視頻播放是一個常見的功能場景&#xff0c;例如短視頻、直播、課程、廣告展示等。 Flutter 本身并沒有直接提供視頻播放器組件&#xff0c;而是依賴第三方庫來實現。 今天要介紹的庫是 flick_video_player&#xff0c;它基于 video_player 封裝&…

編寫cmakelists文件常用語句

cmake_minimum_required (VERSION 3.10) 指定最小版本project(XXXX) 指定項目名字 ---------------set(MAIN_EXEC_NAME dwarf_parser) 定義變量${ MAIN_EXEC_NAME } 變量取值set(CMAKE_CXX_STANDARD 14) 指定c14標準&#xff0c;還有11、17、20等標準…

麒麟桌面系統找不到mbr啟動,并重新安裝grub

根據你提供的情況,“麒麟桌面系統找不到MBR啟動”,這通常是由于GRUB引導損壞、MBR記錄丟失或分區表異常導致的。你可以按照以下步驟重新安裝GRUB并修復MBR啟動: ? 步驟一:準備工具 使用銀河麒麟LiveCD或U盤啟動盤(可用Ventoy制作); 啟動電腦,選擇從U盤或光盤進入Live環…

【音頻字幕】構建一個離線視頻字幕生成系統:使用 WhisperX 和 Faster-Whisper 的 Python 實現

一、背景介紹 對于一端沒有字幕外國視頻、字幕&#xff0c;在不懂外語的情況下&#xff0c;怎么獲取相關內容&#xff1f;作為技術宅&#xff0c;怎么自建搭建一個語音轉文字的環境當前AI技術這么發達&#xff1f; 試試 二、系統設計 音頻提取(僅僅是視頻需要該邏輯、本身就是音…

Linux ALSA架構:PCM_OPEN流程 (二)

一 應用端源碼路徑: external\tinyalsa\pcm.c external\tinyalsa\pcm_hw.cstruct pcm *pcm_open(unsigned int card, unsigned int device,unsigned int flags, struct pcm_config *config) {...pcm->ops &hw_ops;pcm->fd pcm->ops->open(card, device,…

tp5的tbmember表閉包查詢 openid=‘abc‘ 并且(wx_unionid=null或者wx_unionid=‘‘)

閉包查詢 tbmember表閉包查詢查詢 openid‘abc并且islose0并且islogout0并且&#xff08;wx_unionidnull或者wx_unionid’&#xff09; Db::table(tbmember)->where([openid>abc,islose>0,islogout>0])->where(function ($query){$query->where(wx_unioni…

邪修實戰系列(3)

1、第一階段邪修實戰總覽&#xff08;9.1-9.30&#xff09; 把第一階段&#xff08;基礎夯實期&#xff09;的學習計劃拆解成極具操作性的每日行動方案。這個計劃充分利用我“在職學習”的特殊優勢&#xff0c;強調“用輸出倒逼輸入”&#xff0c;確保每一分鐘的學習都直接服務…

【GD32】ROM Bootloader、自定義Bootloader區別

Bootloader是應用程序跑起來之前&#xff0c;用于初始化的一段程序&#xff0c;它分為兩種&#xff0c;ROM Bootloader、自定義Bootloader。GD32芯片出廠時預燒錄在ROM中的Bootloader&#xff08;以下簡稱ROM Bootloader&#xff09;和自己編寫的Bootloader&#xff08;以下簡稱…

Linux防火墻-Firewalld

一、 概述 按表現形式劃分&#xff1a; 軟件防火墻&#xff1a; 集成在系統內部&#xff0c;Linux系統&#xff1a; iptables、firewalld、ufw&#xff1b; windows系統下&#xff1a; windows defender 硬件防火墻&#xff1a; 華為防火墻、思科防火墻、奇安信防火墻、深信服防…

【Qt】PyQt、原生QT、PySide6三者的多方面比較

目錄 引言 一、基本定義 二、核心對比維度 1. 編程語言與開發效率 2. 功能與 API 兼容性 3. 性能表現 4. 許可證與商業使用 5. 社區與文檔支持 三、遷移與兼容性 四、適用場景推薦 五、總結對比表 總結 引言 PySide6、PyQt&#xff08;通常指 PyQt5/PyQt6&#xf…

JavaWeb站內信系統 - 技術設計文檔

1. 系統概述1.1 項目背景本系統旨在為企業或社區平臺提供一套完整的站內信解決方案&#xff0c;支持用戶之間的消息發送、接收、管理等功能&#xff0c;提升用戶間的溝通效率。1.2 設計目標實現用戶間消息發送和接收支持一對一和一對多消息發送提供消息狀態跟蹤&#xff08;已讀…

Java基礎 9.10

1.System類常見方法和案例exit&#xff1a;退出當前程序arraycopy&#xff1a;復制數組元素&#xff0c;比較適合底層調用&#xff0c;一般使用 Arrays.copyOf 完成復制數組int[] src{1,2,3};int[] dest new int[3]; System.arraycopy(src, 0, dest, 0, 3);currentTimeMilens&…

詳解flink性能優化

1. 簡介 Apache Flink是一個強大的流處理框架&#xff0c;其性能很大程度上取決于內存的使用效率。在大規模數據處理場景中&#xff0c;合理的內存配置和優化可以顯著提升Flink作業的性能和穩定性。本文將深入探討Flink內存優化的各個方面&#xff0c;包括狀態后端選擇、內存配…