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

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());}}

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

相关文章:

  • 鸿蒙正在跨越“生态繁荣阈值”
  • 大语言模型-Transformer
  • html做一个分组散点图图的软件
  • 韩顺平0基础学java——第28天
  • Elasticsearch-ES查询单字段去重
  • 34.构建核心注入代码
  • C++ 61 之 函数模版
  • 【八股系列】shouldComponentUpdate是为了解决什么问题?(React)
  • CentOS OpenVPN 客户端连接配置
  • 椭圆的几何要素
  • 计算机专业的发展前景与选择建议。
  • 主流框架选择:React、Angular、Vue的详细比较
  • 【React】useState 的原理
  • 思聪私生女能继位吗?王健林表态,家族不会亏待
  • 常用的工具:pdf转换器、流程图
  • [译] React v16.8: 含有Hooks的版本
  • 10个确保微服务与容器安全的最佳实践
  • ECS应用管理最佳实践
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • express如何解决request entity too large问题
  • FastReport在线报表设计器工作原理
  • nodejs:开发并发布一个nodejs包
  • NSTimer学习笔记
  • passportjs 源码分析
  • PHP变量
  • Puppeteer:浏览器控制器
  • 闭包--闭包之tab栏切换(四)
  • 从零开始在ubuntu上搭建node开发环境
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 七牛云假注销小指南
  • 如何优雅地使用 Sublime Text
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 正则表达式小结
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • # 数仓建模:如何构建主题宽表模型?
  • #{}和${}的区别?
  • #职场发展#其他
  • (Java)【深基9.例1】选举学生会
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (七)Flink Watermark
  • (未解决)macOS matplotlib 中文是方框
  • (一)认识微服务
  • (转)程序员疫苗:代码注入
  • (转)项目管理杂谈-我所期望的新人
  • .bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别
  • .net core Swagger 过滤部分Api
  • .net core webapi 大文件上传到wwwroot文件夹
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [BFS广搜]迷阵
  • [BUUCTF]-Reverse:reverse3解析