MyBatis-Plus輸出完整SQL(帶參數(shù))的三種方案
為什么 MyBatis Plus 默認(rèn) SQL 日志沒有參數(shù)?
當(dāng)你使用 mybatis-plus
時(shí),可能會(huì)遇到這樣的情況:
Preparing: SELECT id, name, `desc` FROM author WHERE name = ? Parameters: 劉禹錫(String)
這導(dǎo)致 SQL 不能直接執(zhí)行,調(diào)試也不方便。那么,如何打印完整 SQL(帶參數(shù))呢?本篇文章將介紹 3 種實(shí)現(xiàn)方式,并對(duì)比它們的優(yōu)缺點(diǎn)。
方案 1:使用 SqlLogInterceptor(推薦)
從 MyBatis Plus 3.5.3 版本 開始,官方提供了 SqlLogInterceptor,可以自動(dòng)替換 SQL 語句中的 ? 為實(shí)際參數(shù)。
配置方式:
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.SqlLogInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new SqlLogInterceptor()); // ? 讓 SQL 帶參數(shù) return interceptor; } }
效果:
Executing SQL: SELECT id, name, `desc` FROM author WHERE name = '劉禹錫'
優(yōu)點(diǎn):
- 官方支持,無侵入,簡(jiǎn)單易用
- 低性能開銷,僅影響日志輸出
- 適用于 MyBatis Plus
缺點(diǎn):
- 只適用于 MyBatis Plus(普通 MyBatis 需要用方案 2)
方案 2:自定義 MyBatis Interceptor
如果你使用的是 原生 MyBatis,或者想要更靈活的日志格式,可以 自定義 Interceptor
。
編寫 Interceptor:
@Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class}) }) @Slf4j public class SqlInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { long startTime = System.currentTimeMillis(); Object proceed = invocation.proceed(); long endTime = System.currentTimeMillis(); String sql = generateSql(invocation); log.info("\n 執(zhí)行SQL耗時(shí):{}ms \n 執(zhí)行SQL:{}", endTime - startTime, sql); return proceed; } private static String generateSql(Invocation invocation) { MappedStatement statement = (MappedStatement) invocation.getArgs()[0]; Object parameter = invocation.getArgs().length > 1 ? invocation.getArgs()[1] : null; BoundSql boundSql = statement.getBoundSql(parameter); String sql = boundSql.getSql().replaceAll("[\\s]+", " "); for (ParameterMapping param : boundSql.getParameterMappings()) { Object value = boundSql.getAdditionalParameter(param.getProperty()); sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(value))); } return sql; } private static String getParameterValue(Object object) { return object instanceof String ? "'" + object + "'" : String.valueOf(object); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } }
優(yōu)點(diǎn):
- 適用于 原生 MyBatis 和 MyBatis Plus
- 可自定義日志格式,控制輸出內(nèi)容
缺點(diǎn):
- 需要手動(dòng)編寫,稍微復(fù)雜一點(diǎn)
- 性能開銷略大(需要解析 SQL 并替換參數(shù))
方案 3:開啟 MyBatis 日志(手動(dòng)拼接 SQL)
如果只是 臨時(shí)調(diào)試,可以在 application.yml
配置 MyBatis 日志:
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
然后,手動(dòng)拼接 SQL 進(jìn)行調(diào)試。
優(yōu)點(diǎn):
- 無代碼改動(dòng),適合臨時(shí)調(diào)試
缺點(diǎn):
- 仍然是
Preparing: xxx
和Parameters: xxx
的分離格式 - 不能直接復(fù)制執(zhí)行
最佳方案對(duì)比與選擇
方案 | 適用場(chǎng)景 | 侵入性 | 性能開銷 | 適用框架 |
---|---|---|---|---|
SqlLogInterceptor | MyBatis Plus | 無 | 低 | MyBatis Plus |
自定義 Interceptor | 需要特殊格式 | 中等 | 中 | MyBatis & MyBatis Plus |
MyBatis 日志 | 臨時(shí)調(diào)試 | 無 | 低 | MyBatis & MyBatis Plus |
結(jié)論:哪種方式適合你?
- 推薦:使用
SqlLogInterceptor
,簡(jiǎn)單、無侵入,適用于 MyBatis Plus。 - 進(jìn)階:自定義
Interceptor
,適用于 MyBatis,可自定義日志格式。 - 臨時(shí)調(diào)試:開啟 MyBatis 日志,但不自動(dòng)替換
?
。
到此這篇關(guān)于MyBatis-Plus輸出完整SQL(帶參數(shù))的三種方案的文章就介紹到這了,更多相關(guān)MyBatis-Plus輸出完整SQL內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java覆蓋第三方j(luò)ar包中的某一個(gè)類的實(shí)現(xiàn)方法
在我們?nèi)粘5拈_發(fā)中,經(jīng)常需要使用第三方的 jar 包,有時(shí)候我們會(huì)發(fā)現(xiàn)第三方的 jar 包中的某一個(gè)類有問題,或者我們需要定制化修改其中的邏輯,那么應(yīng)該如何實(shí)現(xiàn)呢,本文給大家介紹了Java覆蓋第三方j(luò)ar包中的某一個(gè)類的實(shí)現(xiàn)方法,需要的朋友可以參考下2025-02-02Java基于動(dòng)態(tài)規(guī)劃法實(shí)現(xiàn)求最長(zhǎng)公共子序列及最長(zhǎng)公共子字符串示例
這篇文章主要介紹了Java基于動(dòng)態(tài)規(guī)劃法實(shí)現(xiàn)求最長(zhǎng)公共子序列及最長(zhǎng)公共子字符串,簡(jiǎn)單描述了動(dòng)態(tài)規(guī)劃法的概念、原理,并結(jié)合實(shí)例形式分析了Java使用動(dòng)態(tài)規(guī)劃法求最長(zhǎng)公共子序列以及最長(zhǎng)公共子字符串相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-08-08springboot項(xiàng)目同時(shí)啟動(dòng)web服務(wù)和grpc服務(wù)的方法
本文主要介紹了springboot項(xiàng)目同時(shí)啟動(dòng)web服務(wù)和grpc服務(wù)的方法,通過實(shí)際代碼示例展示了實(shí)現(xiàn),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02基于自定義BufferedReader中的read和readLine方法
下面小編就為大家分享一篇基于自定義BufferedReader中的read和readLine方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12詳解Java并發(fā)編程之內(nèi)置鎖(synchronized)
這篇文章主要介紹了Java并發(fā)編程之內(nèi)置鎖(synchronized)的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03SpringMVC表單提交參數(shù)400錯(cuò)誤解決方案
這篇文章主要介紹了SpringMVC表單提交參數(shù)400錯(cuò)誤解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10SpringBoot實(shí)現(xiàn)文件斷點(diǎn)續(xù)傳功能詳解
在處理大文件傳輸或網(wǎng)絡(luò)不穩(wěn)定的情況下,文件斷點(diǎn)續(xù)傳功能顯得尤為重要,本文將詳細(xì)介紹如何使用Spring Boot實(shí)現(xiàn)文件的斷點(diǎn)續(xù)傳功能,需要的可以了解下2025-04-04