Springboot + Mybatis 实现sql打印

参照这个视频:https://www.bilibili.com/video/BV1MS411N7mn/?vd_source=90ebeef3261cec486646b6583e9f45f5
实现mybatis对外暴露的接口Interceptor
使用@Intercepts接口,这里的写法参照mybatis-plus中的拦截器写法
在这里插入图片描述

@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}),
})
public class MybatisSqlPrint 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 {// 通过generateSql方法拿到最终生成的SQLprintSql = generateSql(invocation);}catch (Exception exception){System.err.println(String.format("获取sql异常:%s",exception));}finally {// 拼接日志打印过程long costTime = endTime - startTime;System.out.println(String.format("\n 执行SQL耗时:%dms \n 执行SQL:%s",costTime,printSql));}return proceed;}private static String generateSql(Invocation invocation){// 获取到BoundSql以及Configuration对象// BoundSql 对象存储了一条具体的 SQL 语句及其相关参数信息。// Configuration 对象保存了 MyBatis 框架运行时所有的配置信息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();// 获取到执行的SQLString sql = boundSql.getSql();// SQL中多个空格使用一个空格代替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);// 检查对象中是否存在该属性的 getter 方法,如果存在就取出来进行替换if (metaObject.hasGetter(propertyName)){Object obj = metaObject.getValue(propertyName);sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));// 检查 BoundSql 对象中是否存在附加参数。附加参数可能是在动态 SQL 处理中生成的,有的话就进行替换}else if (boundSql.hasAdditionalParameter(propertyName)){Object obj = boundSql.getAdditionalParameter(propertyName);sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));}else {// 如果都没有,说明SQL匹配不上,带上“缺失”方便找问题sql = sql.replaceFirst("\\?", "缺失");}}}}return sql;}private static String getParameterValue(Object object) {String value = "";if (object instanceof String){value = "'" + object.toString() + "'";}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;}}

最后将拦截器添加到mybatis中

@Configuration
public class MybatisConfig {public MybatisConfig() {System.out.println("MybatisConfig loaded");}SqlSessionFactory sqlSessionFactory;@Autowiredpublic void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;}@PostConstructpublic void addInterceptor(){sqlSessionFactory.getConfiguration().addInterceptor(new MybatisSqlPrint());}}

实现效果
在这里插入图片描述

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

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

相关文章

BC153 [NOIP2010]数字统计

数字统计 一.题目描述二.输入描述&#xff1a;三.输出描述&#xff1a;四.数字范围五.题目思路六.代码实现 一.题目描述 请统计某个给定范围[L, R]的所有整数中&#xff0c;数字2出现的次数。 比如给定范围[2, 22]&#xff0c;数字2在数2中出现了1次&#xff0c;在数12中出现1次…

如何恢复iPhone iCloud云盘资料删除?给出建议

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

【Java】已解决com.mysql.cj.jdbc.exceptions.CommunicationsException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决com.mysql.cj.jdbc.exceptions.CommunicationsException异常 一、分析问题背景 com.mysql.cj.jdbc.exceptions.CommunicationsException是Java程序在使用MySQL Connector/J与…

目标检测—Fast RCNN

介绍Fast R-CNN之前先简单回顾一下R-CNN和SPP-net R-CNN&#xff08;Regions with CNN&#xff09; affine image wraping 解析 Bounding Box Regression&#xff08;边界框回归&#xff09; 如何回归&#xff1f; 问题1&#xff1a;为什么要使用相对坐标差&#xff1f; …

立创开源学习篇(一)

1.机壳地 外面包围的一圈是机壳地&#xff0c;和金属外壳相连与电路板的GND不相连&#xff1a;&#xff08;大疆很多产品有此设计&#xff09; 屏蔽和接地&#xff1a;通过在电路板周围打孔&#xff0c;并连接到机壳地&#xff0c;可以形成有效的电磁屏蔽层&#xff08;形成金…

【C语言】回调函数 和 部分库函数的用法以及模拟实现

一、回调函数&#xff1a; 1、定义&#xff1a; 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;我们就说这是回调函数。 2、qsort的模拟实现…

怎样打印微信文档文件?

在日常生活和工作中&#xff0c;我们经常需要打印微信中的文档文件&#xff0c;无论是工作资料、学习笔记还是其他重要信息。随着科技的发展&#xff0c;我们不再需要前往打印店进行繁琐的操作&#xff0c;而是可以通过一些便捷的在线打印平台轻松实现。今天&#xff0c;我们就…

echarts学习:通过图例事件实现选中后控制多条折线的显隐

1.问题描述 我在工作中遇到了这样一个需求&#xff1a;我们都知道点击echarts折线图的图例&#xff0c;是可以控制折线的显隐的。我现在希望点击某一个图例可以改变多条折线的显隐。 例如在下面这张图中&#xff0c;我将“xxx水位”和“yyy水位”分为一组&#xff1b;将“xxx…

SGPT论文阅读笔记

这是篇想要用GPT来提取sentence embedding的工作&#xff0c;提出了两个框架&#xff0c;一个是SGPT-BE&#xff0c;一个是SGPT-CE&#xff0c;分别代表了Bi-Encoder setting和Cross-Encoder setting。CE的意思是在做阅读理解任务时&#xff0c;document和query是一起送进去&am…

Maven 配置学习:存在两个本地私服如何配置

Maven 配置学习&#xff1a;存在两个本地私服如何配置 目录 Maven 配置学习&#xff1a;存在两个本地私服如何配置解释&#xff1a;1.本地仓库位置&#xff1a;2.Profiles 定义&#xff1a;3.Repositories 定义顺序&#xff1a;4.Active Profiles&#xff1a; 操作步骤&#xf…

在Pycharm使用Github Copilot

文章目录 1.GitHub Copilot 是什么2.注册GitHub Copilot3.官方使用文档4.安装 GitHub Copilot插件5.在Pycharm中使用6.相关功能键7.启用或禁用 GitHub Copilot 1.GitHub Copilot 是什么 GitHub Copilot 是一款 AI 编码助手&#xff0c;可帮助你更快、更省力地编写代码&#xff…

【MySQL进阶之路 | 高级篇】SQL执行过程

1. 客户端与服务器的连接 运行中的服务器程序与客户端程序本质上都是计算机的一个进程&#xff0c;所以客户端进程向服务器端进程发送请求并得到相应过程的本质就是一个进程间通信的过程. 我们可以使用TCP/IP网络通信协议&#xff0c;命名管道和共享内存等方式&#xff0c;实…

2024/6/18(RBAC,查询用户权限,细粒度授权,选课,支付宝生成二维码支付,支付结果查询需要内网穿透)

黑马程序员【学成在线项目】,P141 测试沙箱支付宝_黑马学成在线支付宝沙箱-CSDN博客 需要内网穿透

31.加载配置文件中的游戏到辅助列表

上一个内容&#xff1a;30.保存游戏配置到文件 以 30.保存游戏配置到文件 它的代码为基础进行修改 效果图&#xff1a; 加载配置文件到列表的函数&#xff1a; void CWndINJ::LoadGame() {int count GetPrivateProfileInt(L"main", L"count", 0, GameI…

通勤必备!重回儿时回忆,完全免费!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 今天给大家安利三个网站&#xff0c;可以完全免费在线玩的小霸王游戏机&#xff0c;重回童年游戏时刻&#xff01; 最后一款还可以网页在线和朋友联机CS、吃鸡、暗黑破坏神、拳皇、恐龙…

【数学】负数

Hello!大家好&#xff0c;我是学霸小羊&#xff0c;今天讲讲负数。 目录 1.负数的概念 2.绝对值 附&#xff1a;c求绝对值方法 3.负数的大小比较 1.负数的概念 比0小的数&#xff0c;叫做负数。 负数全称负实数&#xff0c;负数与正数表示意义相反的量。负数用负号(Min…

[NISACTF 2022]babyserialize(pop链详细分析、构造)

目录 [NISACTF 2022]babyserialize &#xff08;一&#xff09;理清pop链&#xff08;链尾 链头&#xff09;&#xff0c;标注步骤 1. 先找eval、flag这些危险函数和关键字样&#xff08;这是链尾&#xff09; 2.往eval()上面看 3.往$bb()上面看 4.往strtolower()上面看 …

【GD32F303红枫派使用手册】第十六节 USART-DMA串口收发实验

16.1 实验内容 通过本实验主要学习以下内容&#xff1a; 串口DMA工作原理 使用DMA进行串口收发 16.2 实验原理 16.2.1 串口DMA工作原理 在前面ADC章节中&#xff0c;我们介绍了DMA的工作原理&#xff0c;这里就不多做介绍。从GD32F303用户手册中可以查到&#xff0c;各串…

烂笔头笔记:为JDK安装Charles证书,让你的请求能够像在浏览器中那样被抓包

为什么要为JDK安装Charles证书 众所周知&#xff0c;https就是为了防止中间过程被拦截从而导致数据泄密的。若强行加入Charles代理&#xff0c;数据被解密后再被其重新加密&#xff0c;数据已经被“破坏”&#xff0c;客户端从而拒绝建立连接或解析内容。 #mermaid-svg-ksLo5W…

【Linux】—Apache Hive 安装部署

文章目录 前言认识Metadata认识Metastoremetastore三种配置方式 一、安装前准备二、下载hive-3.1.2安装包三、下载完成后&#xff0c;通过xftp6上传到Linux服务器上四、解压Hive安装包五、配置Hive六、内嵌模型安装—Hive元数据配置到Derby七、本地模式安装—Hive元数据配置到M…