首页 > 数据库 >用了MyBatis-PLUS的项目 如何优雅的打印SQL

用了MyBatis-PLUS的项目 如何优雅的打印SQL

时间:2024-08-13 10:18:06浏览次数:13  
标签:String SQL object PLUS sql MyBatis import boundSql

说明

在使用MyBatis-Plus作为ORM框架的时候,会发现默认的日志输出是下面这样的:
image
在参数少并且SQL简单的情况下,这样的SQL我们能通过手动去替换占位符,来获取到真正执行的SQL。但是如果是比较复杂的SQL,或者查询参数比较多的话,一个个替换就比较费时费力了。
我们可以通过实现com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor 这个接口,从实现优雅的打印带有完整参数值的sql

实现InnerInterceptor接口

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;

import java.sql.Connection;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

@Slf4j
public class SqlLogInnerInterceptor implements InnerInterceptor {

    // 重写beforePrepare
    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        BoundSql boundSql = sh.getBoundSql();
        String sql = getSql(boundSql);
        log.info(sql);
    }

    private String getSql(BoundSql boundSql) {
        // 获取到执行的SQL
        String sql = boundSql.getSql();
        // SQL换行替换成空格,多个空格使用一个空格代替
        sql = sql.replaceAll("\r\n", " ")
                .replace("\n", " ")
                .replaceAll("[\\s]+", " ");

        if (CollectionUtil.isEmpty(boundSql.getParameterMappings())) {
            return sql;
        }
        // 各种参数在对象中的路径
        List<String> properties = boundSql.getParameterMappings().stream().map(ParameterMapping::getProperty).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(properties)) {
            return sql;
        }
        // boundSql.getParameterObject() 普通参数所在的类,比如接口参入的参数
        if (boundSql.getParameterObject() != null) {
            JSON parameterObject = JSONUtil.parse(boundSql.getParameterObject());
            for (String property : properties) {
                Object path = JSONUtil.getByPath(parameterObject, property);
                if (ObjectUtils.isNotEmpty(path)) {
                    String value = getParameterValue(path);
                    sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(value));
                    continue;
                }
                // boundSql.getAdditionalParameters() 可以理解为框架定义的参数所在的类,比如分页参数
                Map<String, Object> additionalParameters = boundSql.getAdditionalParameters();
                if (CollectionUtil.isNotEmpty(additionalParameters)) {
                    String object = Convert.toStr(additionalParameters.get(property));
                    sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(object));
                    continue;
                }
                sql = sql.replaceFirst("\\?", "缺失");
            }
            return sql;
        }
        for (String property : properties) {
            Map<String, Object> additionalParameters = boundSql.getAdditionalParameters();
            if (CollectionUtil.isNotEmpty(additionalParameters)) {
                String object = Convert.toStr(additionalParameters.get(property));
                sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(object));
                continue;
            }
            sql = sql.replaceFirst("\\?", "缺失");
        }
        return sql;
    }
    
    private static String getParameterValue(Object object) {
        String value = "";
        if (object instanceof String) {
            value = "'" + object + "'";
        } else if (object instanceof Date) {
            value = "'" + DateUtil.format((Date) object, "yyyy-MM-dd HH:mm:ss") + "'";
        } else if (object instanceof LocalDateTime) {
            value = "'" + LocalDateTimeUtil.format((LocalDateTime) object, "yyyy-MM-dd HH:mm:ss") + "'";
        } else if (!ObjectUtils.isEmpty(object)) {
            value = object.toString();
        }
        return value;
    }
}

将自定义的interceptor注入

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
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 PaginationInnerInterceptor());
        // 自定义优雅打印sql的插件
        interceptor.addInnerInterceptor(new SqlLogInnerInterceptor());
        return interceptor;
    }
}

标签:String,SQL,object,PLUS,sql,MyBatis,import,boundSql
From: https://www.cnblogs.com/shareToAll/p/18356303

相关文章

  • MySQL时区设置和查看
    检查:操作系统的时区MYSQL的时区 中国标准时间(CST)在修改系统时间之后,重新启动MySQL服务器,以确保修改生效。 mysql时区查看‌MySQL时区设置查看全局和会话时区使用命令SELECT@@global.time_zone,@@session.time_zone;可以查看全局和会话的时区设置。......
  • MySQL常用命令增删改查select,update,alter...
    MySQL常用命令增删改查select,update,alter…文章目录MySQL常用命令增删改查select,update,alter...MySQL修改用户密码MySQL删除用户命令MySQL修改用户密码查看MySQL的用户及hostselectuser,hostfrommysql.user;备注host分别代表的连接方式user@‘localh......
  • mysql优化路线
    1.explain查询计划(红色字体表示走了索引)type类型名称解释all全表扫描index便利索引树range对索引树进行范围扫描ref使用非唯一索引或唯一索引前缀进行查询eq_ref多表连接中,使用主键或者唯一索引进行查询const、system根据主键或唯一索引进行查询......
  • Unity 配置 SQLite
    原Github仓库链接:https://github.com/robertohuertasm/SQLite4Unity3d?tab=readme-ov-fileAllyouhavetodotostartusingitinyourproject:Downloadthiszip,extractitscontentand copytheresultingfoldertoyourAssets/Pluginsfolder.Itcontainsthe......
  • C primer plus 6.5 for循环
    for语句:    形式:    for(initialize;test;update)    statement在test为0之前重复执行statement。for语句使用3个表达式控制循环过程,分别用分号隔开。    第一个表达式是初始化,只会在循环开始前执行一次    第二个表达式时测试条......
  • CTF-mysql
    整数型输入1发现有回显发现and1=1有回显1=2没有判断字段数1orderby2确定回显点-1unionselect1,2查看数据库名称-1unionselecr1,database()查看数据库名-1unionslelctgroup_concat(schema_name)frominformation_schema.schemata查看表名......
  • C ++ 也可以搭建Web?高性能的 C++ Web 开发框架 CPPCMS + MySQL 实现快速入门案例
    什么是CPPCMS?CppCMS是一个高性能的C++Web开发框架,专为构建快速、动态的网页应用而设计,特别适合高并发和低延迟的场景。其设计理念类似于Python的Django或RubyonRails,但针对C++提供了更细粒度的控制和更高效的性能。主要特点和优点1.高性能与并发处理​Cp......
  • MySQL数据分析进阶(十三)高效的索引
    ※食用指南:文章内容为‘CodeWithMosh’SQL进阶教程系列学习笔记,笔记整理比较粗糙,主要目的自存为主,记录完整的学习过程。(图片超级多,慎看!)【中字】SQL进阶教程|史上最易懂SQL教程!10小时零基础成长SQL大师!!https://www.bilibili.com/video/BV1UE41147KC/?spm_id_from=333.1007.0.......
  • 【PostgreSQL教程】PostgreSQL GROUP BY 语句
    博主介绍:✌全网粉丝20W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。感兴趣的可以先......
  • 解决:The GPG keys listed for the "MySQL 8.0 Community Server" repository are alre
    安装mysql提示Retrievingkeyfromfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysqlTheGPGkeyslistedforthe"MySQL8.0CommunityServer"repositoryarealreadyinstalledbuttheyarenotcorrectforthispackage.CheckthatthecorrectkeyURLsarecon......