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

MyBatis Plus 输出完整 SQL(带参数)的 3 种方案

📌 目录

    • ❓ 为什么 MyBatis Plus 默认 SQL 日志没有参数?
    • 🚀 方案 1:使用 `SqlLogInterceptor`(推荐 ✅)
    • 🛠 方案 2:自定义 MyBatis `Interceptor`
      • **编写 `Interceptor`:**
    • 🔍 方案 3:开启 MyBatis 日志(手动拼接 SQL)
    • ⚖️ 最佳方案对比与选择
    • 🎯 结论:哪种方式适合你?


❓ 为什么 MyBatis Plus 默认 SQL 日志没有参数?

当你使用 mybatis-plus 时,可能会遇到这样的情况:

Preparing: SELECT id, name, `desc` FROM author WHERE name = ?
Parameters: 刘禹锡(String)

这导致 SQL 不能直接执行,调试也不方便。那么,如何打印完整 SQL(带参数)呢?本篇文章将介绍 3 种实现方式,并对比它们的优缺点。


🚀 方案 1:使用 SqlLogInterceptor(推荐 ✅)

从 MyBatis Plus 3.5.3 版本 开始,官方提供了 SqlLogInterceptor,可以自动替换 SQL 语句中的 ? 为实际参数。

配置方式:

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 带参数
        return interceptor;
    }
}

效果:

Executing SQL: SELECT id, name, `desc` FROM author WHERE name = '刘禹锡'

优点:

  • 官方支持,无侵入,简单易用
  • 低性能开销,仅影响日志输出
  • 适用于 MyBatis Plus

🚨 缺点:

  • 只适用于 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 执行SQL耗时:{}ms \n 执行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);
    }
}

优点:

  • 适用于 原生 MyBatisMyBatis Plus
  • 可自定义日志格式,控制输出内容

🚨 缺点:

  • 需要手动编写,稍微复杂一点
  • 性能开销略大(需要解析 SQL 并替换参数)

🔍 方案 3:开启 MyBatis 日志(手动拼接 SQL)

如果只是 临时调试,可以在 application.yml 配置 MyBatis 日志:

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

然后,手动拼接 SQL 进行调试。

优点:

  • 无代码改动,适合临时调试

🚨 缺点:

  • 仍然是 Preparing: xxxParameters: xxx 的分离格式
  • 不能直接复制执行

⚖️ 最佳方案对比与选择

方案适用场景侵入性性能开销适用框架
SqlLogInterceptorMyBatis PlusMyBatis Plus
自定义 Interceptor 🚀需要特殊格式中等MyBatis & MyBatis Plus
MyBatis 日志 🛠临时调试MyBatis & MyBatis Plus

🎯 结论:哪种方式适合你?

  • 推荐 ✅:使用 SqlLogInterceptor,简单、无侵入,适用于 MyBatis Plus
  • 进阶 🚀:自定义 Interceptor,适用于 MyBatis,可自定义日志格式。
  • 临时调试 🛠:开启 MyBatis 日志,但不自动替换 ?

http://www.kler.cn/a/534112.html

相关文章:

  • 【免费】2007-2019年各省科技支出占一般公共预算支出的比重数据
  • 《redis4.0 通信模块源码分析(一)》
  • Immutable设计 SimpleDateFormat DateTimeFormatter
  • C++ 学习:深入理解 Linux 系统中的冯诺依曼架构
  • k8m 是一款轻量级、跨平台的 Kubernetes 仪表板
  • pycharm(2)
  • Boosting 框架
  • 硬件工程师思考笔记02-器件的隐秘角落:磁珠与电阻噪声
  • 堆的实现——堆的应用(堆排序)
  • CTFSHOW-WEB入门-PHP特性89-100
  • 基于SpringBoot+MySQL的图书借阅管理系统源代码+数据库
  • 稳定Android Studio2021.1.2.16的安装
  • flutter 专题四十四 关于MacOs Catalina “无法打开***,因为无法验证开发者...”的解决方案
  • C语言:把两个16位的数据合成32位浮点型数据
  • 基于 docker 的mysql 5.7 主备集群搭建
  • 【PDF多区域识别】如何批量PDF指定多个区域识别改名,基于Windows自带的UWP的文字识别实现方案
  • 第五十八节 k8s1.30.x 安装Redis集群
  • Redis --- 使用Feed流实现社交平台的新闻流
  • 【C++】STL——list底层实现
  • Java基础进阶
  • vue 学习笔记 - 2、简单的一个例子
  • vscode修改自定义模板
  • DeepSeek图解,10页小册子,PDF开放下载!
  • STM32-启动文件
  • Java进阶文件输入输出实操(图片拷贝)
  • 安装mindspore_rl踩坑