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

SQL美化器优化

文章目录

    • 1.目录
    • 2.代码

1.目录

CleanShot 2024-10-26 at 19.26.45@2x

2.代码

package com.sunxiansheng.mybatis.plus.inteceptor;import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.*;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.vertical_blank.sqlformatter.SqlFormatter;
import com.github.vertical_blank.sqlformatter.languages.Dialect;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;/*** SQL美化拦截器:显示完整的SQL,并输出执行结果*/
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
})
public class SqlBeautyInterceptor implements Interceptor {private static final Logger logger = LoggerFactory.getLogger(SqlBeautyInterceptor.class);// ANSI 颜色代码private static final String ANSI_RESET = "\u001B[0m";private static final String ANSI_BRIGHT_GREEN = "\u001B[92m";   // 亮绿色(结果)private static final String ANSI_BRIGHT_BLUE = "\u001B[94m";    // 亮蓝色(项目名称)// Gson 实例,用于格式化结果private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();MetaObject metaObject = SystemMetaObject.forObject(statementHandler);// 分离代理对象链while (metaObject.hasGetter("h")) {Object object = metaObject.getValue("h");metaObject = SystemMetaObject.forObject(object);}// 分离最后一个代理对象的目标类while (metaObject.hasGetter("target")) {Object object = metaObject.getValue("target");metaObject = SystemMetaObject.forObject(object);}MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");Configuration configuration = mappedStatement.getConfiguration();long startTime = System.currentTimeMillis();Object result = null;try {// 执行 SQL,获取结果result = invocation.proceed();return result;} finally {long endTime = System.currentTimeMillis();long sqlCost = endTime - startTime;SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();// 使用修改后的 formatSql 方法String formattedSql = formatSql(configuration, boundSql);// 格式化执行结果String formattedResult = formatResult(result, sqlCommandType);// 日志输出logger.info("\n========================\n{}SQL 类型:{} {}{}{}\n{}SQL:{}\n{}{}{}\n{}执行耗时:{} {}{}ms{} \n{}结果:{}\n{}{}\n{}========================{}",ANSI_BRIGHT_BLUE, ANSI_RESET,ANSI_BRIGHT_GREEN, sqlCommandType, ANSI_RESET,ANSI_BRIGHT_BLUE, ANSI_RESET,ANSI_BRIGHT_GREEN, formattedSql, ANSI_RESET,ANSI_BRIGHT_BLUE, ANSI_RESET,ANSI_BRIGHT_GREEN, sqlCost, ANSI_RESET,ANSI_BRIGHT_BLUE, ANSI_RESET,ANSI_BRIGHT_GREEN, formattedResult, ANSI_RESET,ANSI_BRIGHT_BLUE, ANSI_RESET);}}@Overridepublic Object plugin(Object target) {// 使用 Plugin.wrap 生成代理对象return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 可以通过配置文件设置属性}/*** 格式化 SQL,将参数替换到 SQL 中,并使用 SQLFormatter 进行格式化** @param configuration MyBatis 配置对象* @param boundSql      绑定的 SQL* @return 格式化后的 SQL*/private String formatSql(Configuration configuration, BoundSql boundSql) {try {// 获取 SQL 语句String sql = boundSql.getSql();// 获取参数对象Object parameterObject = boundSql.getParameterObject();// 获取参数映射List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null && !parameterMappings.isEmpty() && parameterObject != null) {TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();MetaObject metaObject = configuration.newMetaObject(parameterObject);// 替换 SQL 中的参数占位符for (ParameterMapping parameterMapping : parameterMappings) {String propertyName = parameterMapping.getProperty();Object value;if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (metaObject.hasGetter(propertyName)) {value = metaObject.getValue(propertyName);} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {value = null;}sql = replaceFirstQuestionMark(sql, getParameterValue(value));}}// 使用 SQLFormatter 格式化 SQLreturn SqlFormatter.of(Dialect.MySql).format(sql);} catch (Exception e) {logger.error("Error formatting SQL: ", e);return boundSql.getSql();}}private String replaceFirstQuestionMark(String sql, String value) {return sql.replaceFirst("\\?", Matcher.quoteReplacement(value));}private String getParameterValue(Object obj) {if (obj == null) {return "null";}if (obj instanceof String) {return "'" + obj + "'";}if (obj instanceof Number) {return obj.toString();}if (obj instanceof java.util.Date || obj instanceof java.sql.Date || obj instanceof java.sql.Timestamp) {return "'" + obj.toString() + "'";}return "'" + obj.toString() + "'";}/*** 格式化 SQL 执行结果** @param result         执行结果* @param sqlCommandType SQL 类型* @return 格式化后的结果字符串*/private String formatResult(Object result, SqlCommandType sqlCommandType) {if (result == null) {return "null";}try {String formattedResult;if (sqlCommandType == SqlCommandType.SELECT) {// 查询语句,结果通常是 ListformattedResult = GSON.toJson(result);} else if (sqlCommandType == SqlCommandType.UPDATE || sqlCommandType == SqlCommandType.DELETE || sqlCommandType == SqlCommandType.INSERT) {// 更新语句,结果是受影响的行数formattedResult = result.toString() + " 行受影响";} else {// 其他类型formattedResult = result.toString();}// 可根据需要限制结果输出长度,避免日志过大int maxLength = 2000;if (formattedResult.length() > maxLength) {formattedResult = formattedResult.substring(0, maxLength) + "... [结果过长,已截断]";}return formattedResult;} catch (Exception e) {logger.error("Error formatting result: ", e);return result.toString();}}
}

相关文章:

SQL美化器优化

文章目录 1.目录2.代码 1.目录 2.代码 package com.sunxiansheng.mybatis.plus.inteceptor;import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.*; import org.apache.ibatis.plugin.*; import org.apache.ibatis.reflection.*…...

我的128天创作之路:回顾与展望

大家好呀&#xff01;今天来和你们分享一下我的创作历程&#x1f601;。 一、机缘 最开始创作呢&#xff0c;是因为在学习 C 的 STL 时&#xff0c;像 string、list、vector 这些模板可把我折腾得够呛&#xff0c;但也让我学到了超多东西&#xff01;我就想&#xff0c;要是把我…...

内核配置参数整理

#参考网页 linux5.2 &#xff1c;.config&#xff1e;文件注释 详细解释 CONFIG_ARMy&#xff1a;启用ARM架构支持&#xff0c;这是ARM处理器专用的内核配置选项。 CONFIG_ARM_HAS_SG_CHAINy&#xff1a;启用对散列表&#xff08;scatter-gather&#xff09;链的支持&#xf…...

SpringBoot整合Easy-es

一.什么是Easy-Es Easy-Es&#xff08;简称EE&#xff09;是一款基于ElasticSearch(简称Es)官方提供的RestHighLevelClient打造的ORM开发框架&#xff0c;在 RestHighLevelClient 的基础上,只做增强不做改变&#xff0c;为简化开发、提高效率而生,您如果有用过Mybatis-Plus(简称…...

于交错的路径间:分支结构与逻辑判断的思维协奏

大家好啊&#xff0c;我是小象٩(๑ω๑)۶ 我的博客&#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家&#xff0c;希望能够和大家一起交流学习&#xff0c;共同进步。* 这一节内容很多&#xff0c;文章字数达到了史无前例的一万一&#xff0c;我们要来学习分支与循环结构中…...

Linux之读者写者模型与特殊锁的学习

目录 读者写者模型 特殊锁 悲观锁 自旋锁 在前几期&#xff0c;我们学习了多线程的生产者和消费者模型&#xff0c;生产者和消费者模型中&#xff0c;有三种关系&#xff0c;两个角色&#xff0c;一个场所&#xff0c;那么读者写者模型和生产者消费者模型有什么关联吗&…...

回溯专题 记录

回溯的题目按照这套模板进行&#xff1b; 我感觉整体逻辑还是递归&#xff0c;只不过有了pop_back才是回溯概念&#xff1b; class Solution {public:vector<int> path;vector<vector<int>> ans;void backtracking(int n,int k,int startindex){if(path.…...

使用 Python 实现自动化办公(邮件、Excel)

目录 一、Python 自动化办公的准备工作 1.1 安装必要的库 1.2 设置邮件服务 二、邮件自动化处理 2.1 发送邮件 示例代码 注意事项 2.2 接收和读取邮件 示例代码 三、Excel 自动化处理 3.1 读取和写入 Excel 文件 示例代码 3.2 数据处理和分析 示例代码 四、综合…...

贪心算法笔记

贪心算法笔记 大概内容 贪心就是对于一个问题有很多个步骤,我们在每一个步骤中都选取最优的那一个,最后得出答案。就是在一些函数中可行,但是有些比如二次函数,因为它的转折点不一定最优,就是不可行的。那么如何判断贪心呢?有这么几种 看时间复杂度,一般的就是 O ( n…...

Formality:两种等价状态consistency和equality

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 背景 逻辑锥的等价性检查时&#xff0c;存在两种验证模式&#xff1a;一致(consistency)和等同(equality)&#xff0c;要理解这两点&#xff0c;首先得明白综合工具…...

Java Web开发基础:HTML的深度解析与应用

文章目录 前言&#x1f30d;一.B/S 软件开发架构简述&#x1f30d;二.HTML 介绍❄️2.1 官方文档❄️2.2 网页的组成❄️2.3 HTML 是什么❄️2.4html基本结构 &#x1f30d;三.HTML标签1.html 的标签/元素-说明2. html 标签注意事项和细节3.font 字体标签4.标题标签5.超链接标签…...

第30章 汇编语言--- 性能优化技巧

汇编语言是用于直接编程计算机硬件的低级语言&#xff0c;它几乎是一对一地映射到机器指令。因为汇编代码与特定处理器架构紧密相关&#xff0c;所以在讨论性能优化技巧时&#xff0c;通常需要考虑具体的CPU架构和指令集。 以下是一些通用的汇编语言性能优化技巧&#xff0c;并…...

HTB:Paper[WriteUP]

目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 对靶机进行子域…...

数据库中的 DDL、DML 和 DCL

数据库中的 DDL、DML 和 DCL 在数据库的定义与操作中&#xff0c;DDL、DML 和 DCL 是三个核心概念&#xff0c;分别用于不同层面的数据库管理与操作。 1. DDL&#xff08;Data Definition Language&#xff09; - 数据定义语言 定义 DDL 用于定义和管理数据库的结构或模式。…...

OKR 极简史及理解

大家读完觉得有帮助记得点赞和关注&#xff01;&#xff01;&#xff01; 目录 MBO SMART 和 KPI OKR 1. 什么是 OKR&#xff1f; 1.1 Objectives&#xff08;目标&#xff09; 1.2 Key Results&#xff08;关键成果&#xff09; KR 应当是困难的&#xff0c;但并非不可…...

电商项目-基于ElasticSearch实现商品搜索功能(四)

一、 高亮显示 1.1 高亮分析 高亮显示是指根据商品关键字搜索商品的时候&#xff0c;显示的页面对关键字给定了特殊样式&#xff0c;让它显示更加突出&#xff0c;如商品搜索中&#xff0c;关键字变成了红色&#xff0c;其实就是给定了红色样式。 1.2 高亮搜索实现步骤解析 …...

TCP封装数据帧

void *send_data(void *arg) //这是一个发送数据的线程 {int sockfd init_tcp_cli("192.168.0.148",50000) //传ip和port&#xff0c;port 50000是因为大概前五万都被其它服务所占用&#xff0c;50000后是私人ipif(sockfd < 0){return NULL;}unsigned char …...

数据结构与算法之二叉树: LeetCode 515. 在每个树行中找最大值 (Ts版)

在每个树行中找最大值 https://leetcode.cn/problems/find-largest-value-in-each-tree-row/description/ 描述 给定一棵二叉树的根节点 root &#xff0c;请找出该二叉树中每一层的最大值 示例1 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9]示例2 输入: root [1,2,3]…...

百度视频搜索架构演进

导读 随着信息技术的迅猛发展&#xff0c;搜索引擎作为人们获取信息的主要途径&#xff0c;其背后的技术架构也在不断演进。本文详细阐述了近年来视频搜索排序框架的重大变革&#xff0c;特别是在大模型技术需求驱动下&#xff0c;如何从传统的多阶段级联框架逐步演变为更加高…...

构造函数的原型原型链

代码示例 // 定义一个构造函数 Test function Test() {this.name 张三 }; //向构造函数的原型添加一个属性 age18 Test.prototype.age 18;//使用构造函数 Test 来实例化一个新对象 const test new Test();//向 Object.prototype 添加了一个名为 sex 的属性&#xff0c;其值…...

模电设计实践之“音频功率放大器的设计” - 包含OCL主放大器设计、总电路图与框架详解、设计方...

模电设计实践之音频功率放大器的设计&#xff08;word文档&#xff09;文档有详细的参数计算过程 其主要内容是&#xff1a; 1、OCL主放大器的设计 2、总电路图、框架图以及单元电路介绍 3、设计方案论证 4、设计及电路参数计算&#xff0c;元器件选择 5、技术指标校验拆开音响…...

Ostrakon-VL 提示词(Prompt)工程高级技巧:控制输出格式与风格

Ostrakon-VL 提示词&#xff08;Prompt&#xff09;工程高级技巧&#xff1a;控制输出格式与风格 1. 引言&#xff1a;为什么需要掌握Prompt工程&#xff1f; 如果你用过Ostrakon-VL这类多模态大模型&#xff0c;可能遇到过这样的困扰&#xff1a;明明输入了很详细的描述&…...

openclaude:模型接入 Code 工具链

作为一名长期关注人工智能工程化落地的开发者&#xff0c;我深知本地大模型在隐私保护和成本控制上的优势&#xff0c;但往往苦于缺乏像 Claude Code 那样强大的工具调用能力。很多时候&#xff0c;我们拥有强大的模型&#xff08;如 DeepSeek、Ollama 本地部署&#xff09;&am…...

千问3.5-27B中文优化实践:提升OpenClaw指令理解准确率

千问3.5-27B中文优化实践&#xff1a;提升OpenClaw指令理解准确率 1. 为什么需要专门优化中文指令理解 上周我在用OpenClaw整理项目文档时&#xff0c;发现一个有趣现象&#xff1a;当我用英文说"organize these PDFs by date"时&#xff0c;AI能准确按日期分类文件…...

Flutter鸿蒙化适配中遇到的问题

Flutter 环境搭建避坑指南Flutter 作为跨平台开发的热门框架&#xff0c;凭借一套代码多端运行的优势&#xff0c;深受开发者喜爱&#xff0c;但环境搭建与适配却是新手入门的第一道拦路虎。我在初次配置 Flutter 开发环境时&#xff0c;接连踩中环境变量、模拟器版本、第三方工…...

跨平台办公自动化:OpenClaw+千问3.5-27B同步多端文件

跨平台办公自动化&#xff1a;OpenClaw千问3.5-27B同步多端文件 1. 为什么需要跨平台文件同步&#xff1f; 作为一个常年需要在Windows和Mac双系统切换的开发者&#xff0c;我经历过无数次这样的尴尬时刻&#xff1a;在Mac上修改的文档忘传到Windows&#xff0c;开会时找不到…...

气动元器件选型(工业自动化场景实战指南)

1. 气动技术基础与工业自动化适配性 气动技术作为工业自动化领域的核心驱动方式之一&#xff0c;其本质是通过压缩空气实现能量传递。想象一下&#xff0c;就像我们用吸管吹动纸团一样简单直接——空压机将电动机的旋转动能转化为气压能&#xff0c;再通过各类阀门控制气流方向…...

lite-avatar形象库效果展示:教师数字人在直播授课场景中的眼神交互与手势模拟

lite-avatar形象库效果展示&#xff1a;教师数字人在直播授课场景中的眼神交互与手势模拟 1. 引言&#xff1a;当数字人老师走进直播间 想象一下&#xff0c;你正在准备一场面向数千名学生的在线直播课。除了精心准备的课件和讲稿&#xff0c;你还需要一个能清晰传达知识、与…...

边缘检测算法选型指南:从Sobel到Canny的5个实际场景对比(含医疗/自动驾驶案例)

边缘检测算法实战选型&#xff1a;医疗影像与自动驾驶场景下的Sobel与Canny深度评测 在计算机视觉领域&#xff0c;边缘检测作为图像处理的基础环节&#xff0c;直接影响着后续特征提取和目标识别的准确性。面对医疗影像分析、自动驾驶感知等对精度和实时性要求极高的场景&…...

PyTorch版本升级踩坑实录:从1.10.0到1.10.1为何导致CUDA不兼容?

PyTorch小版本升级的隐秘陷阱&#xff1a;CUDA兼容性深度解析与实战解决方案 当你满怀期待地执行pip install --upgrade torch命令&#xff0c;将PyTorch从1.10.0升级到1.10.1时&#xff0c;可能不会想到这个看似无害的小版本更新会让你的GPU突然"罢工"。这不是个例…...