MyBatis如何自定义项目中SQL日志

说明:用过MyBatis框架的同学们都知道,打印SQL日志,可以通过在application.yml配置文件中加入下面配置来设置:

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

但打印出来的SQL如下,丑陋不堪,不够优雅

在这里插入图片描述

本文介绍如何自定义SQL日志

拦截器

首先,创建一个拦截器,这个拦截器可以拦截住所有访问数据库的操作,在这里面我们可以自己去拼接想要的信息,打印出SQL日志,如下:

import lombok.extern.log4j.Log4j2;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.util.ObjectUtils;import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;@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}),@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
@Log4j2
public class MybatisInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 记录执行SQL前后的时间戳long startTime = System.currentTimeMillis();Object proceed = invocation.proceed();long endTime = System.currentTimeMillis();String printSql = null;try {// 获取执行的SQL, 注意这里没有把拼接SQL放在endTime前面,所以拼接SQL日志是不影响计算的SQL执行时间的。printSql = generateSql(invocation);} catch (Exception exception) {log.error("获取sql异常", exception);} finally {long costTime = endTime - startTime;log.info("【执行的SQL:{}, 耗时:{}ms】", printSql, costTime);}return proceed;}/*** 拼接执行的SQL*/private static String generateSql(Invocation invocation) {MappedStatement statement = (MappedStatement) invocation.getArgs()[0];Object parameter = null;if (invocation.getArgs().length > 1) {parameter = invocation.getArgs()[1];}Configuration configuration = statement.getConfiguration();BoundSql boundSql = statement.getBoundSql(parameter);// 获取参数对象Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> params = boundSql.getParameterMappings();// 获取执行的SQL ==> SELECT id,username,password FROM i_users WHERE id = ?String sql = boundSql.getSql();// 多个空格,用一个空格代替sql = sql.replaceAll("[\\s]+", " ");if (!ObjectUtils.isEmpty(params) && !ObjectUtils.isEmpty(parameterObject)) {// TypeHandlerRegistry 是 MyBatis 用来管理 TypeHandler 的注册器。TypeHandler 用于在 Java 类型和 JDBC 类型之间进行转换TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();// 如果参数对象的类型有对应的 TypeHandler,则使用 TypeHandler 进行处理if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(parameterObject)));} else {// 否则,逐个处理参数映射for (ParameterMapping param : params) {String propertyName = param.getProperty();MetaObject metaObject = configuration.newMetaObject(parameterObject);if (metaObject.hasGetter(propertyName)) {Object obj = metaObject.getValue(propertyName);sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));} else if (boundSql.hasAdditionalParameter(propertyName)) {Object obj = boundSql.getAdditionalParameter(propertyName);sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));} else {sql = sql.replaceFirst("\\?", "缺失");}}}}return sql;}/*** 获取参数值*/private static String getParameterValue(Object object) {String value = "";if (object instanceof String) {value = "'" + object + "'";} else if (object instanceof Date) {DateFormat format = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);value = "'" + format.format((Date) object) + "'";} else if (!ObjectUtils.isEmpty(object)) {value = object.toString();}return value;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}
}

创建完拦截器,再创建一个配置类,将这个拦截器注入到IOC里,如下:

import com.hezy.inteceptor.MybatisInterceptor;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyBatisConfig {@Beanpublic ConfigurationCustomizer mybatisConfigurationCustomizer() {return configuration -> {configuration.addInterceptor(new MybatisInterceptor());};}
}

测试

现在,把前面的日志配置去掉。启动项目,访问数据库,查看效果,如下:

在这里插入图片描述

非常nice,是不是

总结

本文介绍如何通过MyBatis拦截器,自定义SQL日志,参考微信公众号【小白翻身日志】的文章

  • 用了MyBatis的项目 如何优雅地打印SQL

关于MyBatis拦截器的其他使用,可参看下面这篇文章:

  • 数据加密的两种方案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/409797.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习/数据分析--通俗语言带你入门决策树(结合分类和回归案例)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 机器学习是深度学习和数据分析的基础&#xff0c;接下来将更新常见的机器学习算法注意&#xff1a;在打数学建模比赛中&#xff0c;机器学习用的也很多&a…

NVIDIA将在Hot Chips 2024会议上展示Blackwell服务器装置

NVIDIA 将在 Hot Chips 2024 上展示其 Blackwell 技术堆栈&#xff0c;并在本周末和下周的主要活动中进行会前演示。对于 NVIDIA 发烧友来说&#xff0c;这是一个激动人心的时刻&#xff0c;他们将深入了解NVIDIA的一些最新技术。然而&#xff0c;Blackwell GPU 的潜在延迟可能…

企事业单位数据资料防外泄如何实现?这5个小技巧等你来掌握!

企事业单位的数据资料防外泄是一项重要的任务&#xff0c;它关乎企业的核心竞争力和信息安全。 以下是五个实用的小技巧&#xff0c;可以帮助企事业单位有效地防止数据外泄&#xff1a; 1. 数据加密 技巧说明&#xff1a;通过对敏感数据进行加密处理&#xff0c;即使数据被非…

外贸管理软件一般都有哪些功能

外贸管理软件通常被设计来帮助国际贸易企业高效管理其业务流程。这类软件的功能多样&#xff0c;这里以神卓外贸管理软件为例&#xff0c; 以下是一些常见的核心功能模块&#xff1a; 客户关系管理 (CRM) 客户信息管理询盘与报价管理销售机会跟踪 订单管理 订单生成与处理发货…

Sparse Kernel Canonical Correlation Analysis

论文链接&#xff1a;https://arxiv.org/pdf/1701.04207 看这篇论文终于看懂核函数了。。谢谢作者

Azure OpenAI citations with message correlation

题意&#xff1a;“Azure OpenAI 引用与消息关联” 问题背景&#xff1a; I am trying out Azure OpenAI with my own data. The data is uploaded to Azure Blob Storage and indexed for use with Azure AI search “我正在尝试使用自己的数据进行 Azure OpenAI。数据已上传…

中介者模式详解

中介者模式 简介通过引入一个中介者对象来封装和协调多个对象之间的交互&#xff0c;从而降低对象间的耦合度。 人话:就是两个类或者系统之间, 不要直接互相调用, 而是要中间的类来专门进行交互。 举个例子 比如两个国家之间(关系差, 没有大使馆), 需要联合国作为中介进行对话…

公园的客流统计意义何在,有哪些积极作用

随着城市化进程的加快&#xff0c;人们越来越重视休闲娱乐和亲近自然的机会。公园作为市民休闲放松的重要场所&#xff0c;其管理和维护的质量直接影响着市民的生活质量和城市的形象。客流统计在公园管理中扮演着重要角色&#xff0c;不仅可以帮助公园管理者更好地理解游客的行…

大模型网络安全能力和风险评估框架Cybench

大模型网络安全能力和风险评估框架Cybench 前言 语言模型在网络安全领域的双重应用&#xff0c;既可以用于攻击&#xff08;如识别并利用代码漏洞&#xff09;&#xff0c;也可以用于防御&#xff08;如渗透测试和漏洞检测&#xff09;。当前的研究包括对CTF挑战、代码片段中的…

LLM 培训

步骤 1 # 预训练 步骤 1 # 预训练 在预训练阶段,该模型被训练为互联网规模数据上的下一个单词预测器。 在预训练阶段 从互联网上收集大量多样化的数据集。此数据集包含来自各种来源的文本,以确保模型能够学习广泛的语言模式。清理和预处理数据以消除噪音、格式问题和不相关的…

CSS文本样式(一)

一、font-family 1、font-family属性 font-family​ &#xff1a;属性指定元素的​字体​&#xff0c;语法格式如下&#xff1a; ​font-family​: 字体1,字体2,...; 有两种字体系列名称&#xff1a; ​字体系列​&#xff1a;特定的字体系列&#xff08;如Times New Rom…

大型公司网络系统集成方案

一、前言 1.1.公司综合信息系统建设目标 -----------------------------------------------------3 1.2. 用户具体需求----------------------------------------------------------------------------4 1.3.公司综合信息系统建设原则 -------------------------------…

SpringBoot集成kafka接收对象消息

SpringBoot集成kafka接收对象消息 1、生产者2、消费者3、工具类4、消息实体对象5、配置文件6、启动类7、测试类8、测试结果 1、生产者 package com.power.producer;import com.power.model.User; import com.power.util.JSONUtils; import org.springframework.kafka.core.Kaf…

基于SSM的学生信息管理系统的设计与实现 (含源码+sql+视频导入教程+文档+VISIO图)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的学生信息管理系统12拥有三种角色&#xff1a;学生、教师、管理员 学生&#xff1a;选课、查看已选课程、查看成绩 教师&#xff1a;成绩管理 管理员&#xff1a;课程管理、学生…

两个实用的Python编程技巧

一、变量类型声明技巧 虽然在Python中可以不用声明变量的类型&#xff0c;但是为了加快程序的运算速度&#xff0c;减少不必要的bug&#xff0c;我们可以在定义变量之初就把它的类型确定&#xff0c;这样可以更好地传输变量值。如下面的例子。 我们定义了两个变量&#xff0c…

linux 系统备份与恢复方法及解决方案

&#x1f600;前言 本篇博文是关于 linux 系统备份与恢复&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动力&#x…

Jmeter提取token并设置为全局变量

参考文章&#xff1a;Jmeter提取token并设置为全局变量&#xff08;最详细的步骤&#xff09;_jmeter提取token到全局变量-CSDN博客 一般来说&#xff0c;系统内大多数接口&#xff0c;都需要先获取登录后的token值&#xff0c;所以我们需要创建一个获取token的接口&#xff0c…

4款文章生成器,自动写作优质文章

在当今信息爆炸的时代&#xff0c;内容创作已经成为网络世界中不可或缺的一部分。然而&#xff0c;随着人们对高质量内容的需求不断增加&#xff0c;传统的手动创作已经无法满足市场的需求。因此&#xff0c;文章生成器应运而生&#xff0c;成为许多从业者和企业的利器。在本文…

发完朋友圈就“退款”?黑神话的玩家是否都是“忠实粉丝”?

​声明&#xff1a;此篇为 ai123.cn 原创文章&#xff0c;转载请标明出处链接&#xff1a;https://ai123.cn/2228.html 《黑神话&#xff1a;悟空》自上线以来&#xff0c;便引发了玩家社区的广泛讨论。游戏的退款现象主要受到了一些技术问题和个人体验差异的影响。部分玩家因遇…

Java-Redis

文章目录 基础基础内容使用场景/功能常见数据类型下载与安装可视化&#xff08;多个&#xff09;发布订阅功能事务两种持久化主从模式哨兵模式集群模式Cluster缓存淘汰过期删除缓存一致 Cache Aside缓存击穿缓存穿透缓存雪崩分布式锁 实战内容配置文件配置Redis的BeanRedis为什…