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,一经查实,立即删除!

相关文章

CMake编译proto的方法(custom_target和custom_command)

最近在项目中涉及到在QNX平台上编译CyberRT&#xff0c;其中CyberRT使用到了protobuf&#xff0c;因此&#xff0c;仓库内部有许多proto文件&#xff0c;需要先行将这些proto文件生成对应的.cc和.h文件才能被其他文件使用。 之前一直使用protobuf_generate_cpp来编译proto文件&…

如何在C++中实现延迟删除功能

在软件开发中&#xff0c;缓存是一种常见的优化技术&#xff0c;它允许我们存储数据以供快速访问&#xff0c;从而减少对慢速存储或网络资源的依赖。然而&#xff0c;有时我们可能希望缓存中的某些数据在一段时间后自动过期并被删除&#xff0c;这就是所谓的“延迟删除”功能。…

HTB Freelancer

Freelancer user nmap ➜ htb nmap -A 10.129.221.155 -T 4 Starting Nmap 7.80 ( https://nmap.org ) at 2024-06-02 09:19 CST NSE Timing: About 97.92% done; ETC: 09:24 (0

PostgreSQL源码分析——COPY

导入数据的几种方式 在进行数据导入导出时常会用到copy命令&#xff0c;语法使用可参考下面这篇博文 [Postgres] Bulk Insert and Export Data with csv Files with Postgres copy Command。通常导入数据的方法&#xff0c;可以通过insert的方式&#xff08;insert into t1 va…

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; …

全面对比与选择指南:Milvus、PGVector、Zilliz及其他向量数据库

本文全面探讨了Milvus、PGVector、Zilliz等向量数据库的特性、性能、应用场景及选型建议&#xff0c;通过详细的对比分析&#xff0c;帮助开发者和架构师根据具体需求选择最合适的向量数据库解决方案。 文章目录 向量数据库概述向量数据库的关键功能向量数据库的扩展和选择向量…

立创开源学习篇(一)

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

004、KMeans和DBSCAN的比较

KMeans 聚类 工作原理 选择K个初始中心点&#xff08;可以随机选择或使用其他方法&#xff09;。迭代过程&#xff1a; 分配每个数据点到最近的中心点&#xff1a;计算每个数据点到所有中心点的距离&#xff0c;将数据点分配到最近的中心点所属的簇。更新中心点&#xff1a;计…

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

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

怎样打印微信文档文件?

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

微信小程序自定义组件(写一个点击查看大图有关闭按钮,复制即可使用)

今天碰到一个需求&#xff0c;本来使用wx.previewImage用的好好的&#xff0c;非要加一个关闭按钮&#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…

IPv6改造是什么意思?网站IPv6改造怎么做?

随着互联网技术的飞速发展&#xff0c;IPv4地址资源短缺的问题日益凸显&#xff0c;已经难以满足物联网、人工智能等新基建的激增需求。为了解决这一困境&#xff0c;IPv6协议应运而生&#xff0c;其海量的地址资源和内置的安全机制为互联网的持续发展提供了广阔空间。目前各行…

kbadminv1版后台快速开发框架

探索高效开发的新境界&#xff01;kbadminv1 版后台快速开发框架震撼登场&#xff01; 基于强大的 thinkphp6 框架&#xff0c;kbadminv1 为开发者们带来了前所未有的便捷与高效。 它犹如一把智慧的钥匙&#xff0c;轻松开启后台开发的大门。简洁而直观的设计&#xff0c;让复…

2024-06-18 blue-VH-driver-订阅组态相关分析

摘要: 2024-06-18 blue-VH-driver-订阅组态相关分析 订阅组态相关: 1.1 创建订阅分组成功, 但是激活订阅分组失败 调用VH接口删除已经创建的订阅分组 无论否删除成功,都返回不做重试删除已经创建的订阅分组,避免无法结束调用1.2 向订阅分组添加的位号的数据量超过单个订阅分…

高并发系统中面临的问题 及 解决方案

在互联网软件系统中,高并发读写场景会带来一系列复杂的问题。以下是详细的分析和解决方案: 1. 性能瓶颈 问题: 数据库性能瓶颈:高并发请求会导致数据库负载过重,响应时间增加,甚至可能导致数据库崩溃。服务器性能瓶颈:服务器的CPU、内存、网络带宽可能无法承受高并发请…