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

告别MyBatis-Plus的混乱日志!用P6Spy 1.9.0 + SQL Formatter打造Spring Boot专属SQL监控台

打造Spring Boot专属SQL监控台P6Spy与SQL Formatter的完美实践每次调试复杂的数据库操作时你是否也厌倦了在控制台翻找那些杂乱无章的SQL日志MyBatis-Plus默认的日志输出虽然功能强大但在实际开发中却常常让人头疼——关键信息被淹没在大量无关内容中格式混乱难以阅读执行时间等重要指标需要手动计算。这些问题不仅降低了调试效率还增加了排查问题的难度。本文将带你构建一个专属于Spring Boot项目的SQL监控台通过P6Spy 1.9.0和SQL Formatter的组合实现SQL语句的优雅格式化展示、执行时间自动计算、关键信息高亮等功能。这个方案特别适合以下场景需要频繁调试复杂SQL的业务开发性能优化时需要分析SQL执行效率团队协作时希望统一SQL日志格式教学演示时需要清晰展示SQL执行过程1. 环境准备与依赖配置1.1 添加必要依赖首先在项目的pom.xml中添加P6Spy和SQL Formatter的依赖!-- P6Spy核心依赖 -- dependency groupIdcom.github.gavlyukovskiy/groupId artifactIdp6spy-spring-boot-starter/artifactId version1.9.0/version /dependency !-- SQL格式化工具 -- dependency groupIdcom.github.vertical-blank/groupId artifactIdsql-formatter/artifactId version2.0.4/version /dependency这两个库的组合将为我们提供SQL拦截与日志记录P6SpySQL语句自动美化SQL Formatter执行时间精确统计自定义日志格式能力1.2 配置数据源代理修改application.yml中的数据库连接配置让P6Spy能够拦截所有SQL语句spring: datasource: driver-class-name: com.p6spy.engine.spy.P6SpyDriver url: jdbc:p6spy:mysql://localhost:3306/your_database?useSSLfalseserverTimezoneUTC关键变化点driver-class-name改为P6Spy的驱动类JDBC URL前缀添加p6spy:标识注意请确保保留原有数据库连接参数如时区设置、SSL配置等只需修改驱动和URL前缀即可。2. 实现自定义SQL日志格式2.1 创建P6SpyLogger类核心的自定义日志处理器需要实现MessageFormattingStrategy接口import com.github.vertical_blank.sqlformatter.SqlFormatter; import com.p6spy.engine.spy.appender.MessageFormattingStrategy; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class CustomP6SpyLogger implements MessageFormattingStrategy { private static final DateTimeFormatter TIME_FORMATTER DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss.SSS); Override public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) { if (sql.trim().isEmpty()) { return ; } return String.format(\n ╔════════════════════ SQL 执行日志 ════════════════════╗\n ║ 执行时间: %s\n ║ 执行耗时: %dms\n ║ 连接ID: #%d\n ╠══════════════════════════════════════════════════════╣\n %s\n ╚══════════════════════════════════════════════════════╝, LocalDateTime.now().format(TIME_FORMATTER), elapsed, connectionId, SqlFormatter.format(sql) ); } }这个实现提供了清晰的边框设计增强可读性自动格式化的SQL语句执行时间和耗时统计连接标识便于追踪2.2 配置spy.properties在resources目录下创建spy.properties文件# 指定自定义日志格式类 logMessageFormatcom.your.package.CustomP6SpyLogger # 输出到控制台 appendercom.p6spy.engine.spy.appender.StdoutLogger # 启用慢SQL检测2秒阈值 outagedetectiontrue outagedetectioninterval2 # 排除不重要的日志类别 excludecategoriesinfo,debug,result,commit,resultset # 日期格式 dateformatyyyy-MM-dd HH:mm:ss.SSS # 其他配置 deregisterdriverstrue useprefixtrue3. 与MyBatis-Plus的协同配置3.1 关闭MyBatis-Plus原生日志为了避免日志重复输出需要在application.yml中禁用MyBatis-Plus的日志mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl3.2 解决常见冲突问题在实践中可能会遇到以下问题问题现象解决方案日志重复输出检查是否同时启用了P6Spy和MyBatis日志SQL格式化异常确保SQL Formatter版本兼容性能明显下降调整excludecategories减少不必要日志特殊字符显示异常在spy.properties中配置正确的字符编码4. 高级定制与优化4.1 添加执行计划信息增强版日志处理器可以包含执行计划// 在formatMessage方法中添加 String executionPlan \n║ 执行计划: \n getExecutionPlan(connectionId, sql); private String getExecutionPlan(int connectionId, String sql) { // 实际项目中可通过JDBC获取执行计划 return ║ (此处可添加真实的执行计划分析); }4.2 支持多数据源配置对于多数据源项目需要为每个数据源单独配置Bean ConfigurationProperties(app.datasource.first) public DataSource firstDataSource() { return DataSourceBuilder.create() .driverClassName(com.p6spy.engine.spy.P6SpyDriver) .url(jdbc:p6spy:mysql://host1/db1) .build(); } Bean ConfigurationProperties(app.datasource.second) public DataSource secondDataSource() { return DataSourceBuilder.create() .driverClassName(com.p6spy.engine.spy.P6SpyDriver) .url(jdbc:p6spy:mysql://host2/db2) .build(); }4.3 性能优化建议生产环境配置# 关闭非必要日志 excludecategoriesinfo,debug,result,commit,resultset,batch # 只记录慢查询 outagedetectiontrue outagedetectioninterval100开发环境配置# 记录完整SQL信息 excludecategoriesinfo,debug # 所有SQL都记录 outagedetectionfalse5. 实际效果对比5.1 默认日志 vs 优化后日志原始MyBatis-Plus日志2023-11-15 14:30:22.123 DEBUG 12345 --- [nio-8080-exec-1] c.e.m.m.U.selectByExample : Preparing: SELECT id,name,age FROM user WHERE age ? 2023-11-15 14:30:22.125 DEBUG 12345 --- [nio-8080-exec-1] c.e.m.m.U.selectByExample : Parameters: 18(Integer) 2023-11-15 14:30:22.129 DEBUG 12345 --- [nio-8080-exec-1] c.e.m.m.U.selectByExample : Total: 3优化后日志╔════════════════════ SQL 执行日志 ════════════════════╗ ║ 执行时间: 2023-11-15 14:30:22.123 ║ 执行耗时: 6ms ║ 连接ID: #42 ╠══════════════════════════════════════════════════════╣ SELECT id, name, age FROM user WHERE age 18 ╚══════════════════════════════════════════════════════╝5.2 复杂SQL的展示效果对于多表关联查询优化后的格式优势更加明显╔════════════════════ SQL 执行日志 ════════════════════╗ ║ 执行时间: 2023-11-15 14:35:18.456 ║ 执行耗时: 24ms ║ 连接ID: #57 ╠══════════════════════════════════════════════════════╣ SELECT u.id, u.name, d.department_name, COUNT(o.id) AS order_count FROM users u JOIN departments d ON u.dept_id d.id LEFT JOIN orders o ON u.id o.user_id WHERE u.status ACTIVE AND d.location HQ GROUP BY u.id, u.name, d.department_name HAVING COUNT(o.id) 0 ORDER BY order_count DESC ╚══════════════════════════════════════════════════════╝6. 疑难问题排查指南6.1 常见问题解决方案SQL没有拦截到检查driver-class-name是否正确配置为P6Spy驱动确认URL以jdbc:p6spy:开头验证依赖版本是否兼容日志格式未生效确认spy.properties位于resources根目录检查logMessageFormat配置的类路径是否正确确保没有其他日志配置覆盖性能影响显著调整excludecategories减少日志量考虑只在开发环境启用完整日志升级到P6Spy最新版本6.2 调试技巧启用P6Spy的调试模式# 在spy.properties中添加 autoflushtrue tracetrue tracefilespy.log检查加载的配置// 在应用启动时添加 PostConstruct public void checkP6SpyConfig() { System.out.println(P6Spy配置加载状态: P6SpyOptions.getActiveInstance().getDriverNames()); }7. 扩展应用场景7.1 集成到企业级监控系统将SQL日志接入ELK等日志系统public class ELKP6SpyLogger implements MessageFormattingStrategy { private final Logger elkLogger LoggerFactory.getLogger(SQL_LOGGER); Override public String formatMessage(...) { // 格式化日志内容 String logContent formatLog(connectionId, elapsed, sql); // 发送到ELK elkLogger.info(logContent); // 返回空字符串不在控制台重复输出 return ; } }7.2 基于SQL日志的审计功能增强日志处理器实现审计功能Override public String formatMessage(...) { // 基础日志格式化 String logOutput basicFormat(connectionId, elapsed, sql); // 审计记录 auditService.recordSqlOperation( SecurityContext.getCurrentUser(), sql, elapsed, new Date() ); return logOutput; }7.3 性能分析看板收集SQL指标生成可视化报表// SQL指标收集器 public class SqlMetricsCollector { private static final ConcurrentMapString, SqlStats STATS new ConcurrentHashMap(); public static void recordQuery(String sql, long elapsed) { String normalizedSql normalizeSql(sql); STATS.compute(normalizedSql, (k, v) - { if (v null) { return new SqlStats(elapsed); } v.recordExecution(elapsed); return v; }); } // 提供给监控系统调用的获取接口 public static MapString, SqlStats getStats() { return new HashMap(STATS); } } // 在日志处理器中调用 SqlMetricsCollector.recordQuery(sql, elapsed);8. 最佳实践总结经过多个项目的实践验证以下配置组合效果最佳开发环境配置# 完整SQL日志 logMessageFormatcom.xxx.CustomP6SpyLogger appendercom.p6spy.engine.spy.appender.StdoutLogger excludecategoriesinfo,debug outagedetectionfalse dateformatyyyy-MM-dd HH:mm:ss.SSS测试环境配置# 关注性能指标 logMessageFormatcom.xxx.PerformanceP6SpyLogger appendercom.p6spy.engine.spy.appender.Slf4JLogger excludecategoriesinfo,debug,resultset outagedetectiontrue outagedetectioninterval200生产环境配置# 最小化性能影响 logMessageFormatcom.xxx.BriefP6SpyLogger appendercom.p6spy.engine.spy.appender.Slf4JLogger excludecategoriesinfo,debug,result,commit,resultset,batch,statement outagedetectiontrue outagedetectioninterval500实现这一SQL监控方案后团队在以下方面获得了显著提升调试时间平均减少40%SQL性能问题识别速度提高50%新成员理解数据库操作逻辑的时间缩短60%代码审查时SQL相关问题减少35%

相关文章:

告别MyBatis-Plus的混乱日志!用P6Spy 1.9.0 + SQL Formatter打造Spring Boot专属SQL监控台

打造Spring Boot专属SQL监控台:P6Spy与SQL Formatter的完美实践 每次调试复杂的数据库操作时,你是否也厌倦了在控制台翻找那些杂乱无章的SQL日志?MyBatis-Plus默认的日志输出虽然功能强大,但在实际开发中却常常让人头疼——关键信…...

LabVIEW直流电机性能通用测试系

直流电机在工业控制、智能制造、精密传动等领域应用广泛,其电压、电流、负载扭矩、转速等性能参数的精准测试,是保障电机产品质量、匹配应用工况的关键环节。传统直流电机测试多采用人工操作、单参数检测的方式,存在串口适配繁琐、数据采集实…...

开源Markdown编辑器Cherry Markdown:提升文档处理效率的3大突破

开源Markdown编辑器Cherry Markdown:提升文档处理效率的3大突破 【免费下载链接】cherry-markdown ✨ A Markdown Editor 项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-markdown Cherry Markdown是一款功能强大的开源Markdown编辑器&#xff0c…...

告别截图焦虑!这7款ChromeFK插件,让你一键搞定网页长截图和翻译

告别截图焦虑!7款Chrome插件打造高效网页信息处理工作流 每次遇到需要保存的网页内容,你是否还在反复调整滚动条手动拼接截图?面对满屏英文资料时,是否依然在翻译软件和浏览器之间来回切换?在这个信息过载的时代&#…...

FreeRTOS二值信号量实战:用STM32串口DMA+空闲中断实现高效数据接收(附完整代码)

FreeRTOS二值信号量在STM32串口DMA通信中的实战优化 1. 嵌入式系统中串口通信的挑战与解决方案 在STM32嵌入式开发中,串口通信是最基础也最常用的外设接口之一。传统的中断接收方式虽然简单直接,但在处理高速数据流或不定长数据包时,频繁的中…...

告别Python2依赖!2023年用Kali玩转Wifite的现代替代方案

告别Python2依赖!2023年用Kali玩转Wifite的现代替代方案 在网络安全领域,WiFi渗透测试工具链的迭代速度往往跟不上技术演进的步伐。当Python 2在2020年正式结束生命周期时,许多经典工具却依然固守在这个早已过时的运行时环境上,给…...

WinForm小工具实战:BJ54/XA80坐标批量转WGS84的Excel自动化处理(附C#源码)

WinForm坐标转换工具实战:从BJ54/XA80到WGS84的高效批量处理方案 在测绘、GIS开发或城市规划领域,坐标转换是日常工作中不可或缺的环节。面对成百上千个坐标点的批量转换需求,手动操作不仅效率低下,还容易引入人为错误。本文将分享…...

Mem0: 构建具有可扩展长期记忆的生产级 AI 智能体

作者: HOS(安全风信子) 日期: 2026-03-21 主要来源平台: HuggingFace 摘要: Mem0 提出了一种以记忆为中心的可扩展架构,通过动态提取、整合和检索对话中的显著信息,解决了 LLM 固定上下文窗口的局限性。本文…...

OpenClaw-RL: 通过对话训练任意智能体的全新框架

作者: HOS(安全风信子) 日期: 2026-03-21 主要来源平台: HuggingFace 摘要: OpenClaw-RL 提出了一种创新框架,通过利用各种交互模态的下一状态信号进行策略学习,实现了智能体的持续改进。本文深入分析其核心…...

共享打印机连接失败?深入解析错误0x00000709背后的DNS机制与两种修复方案

共享打印机连接失败?深入解析错误0x00000709背后的DNS机制与两种修复方案 当你在办公室尝试连接一台共享打印机时,突然弹出一个令人困惑的错误提示:"操作不能完成(错误0x00000709)"。这种情况尤其令人沮丧&a…...

CH579/CH573/CH582/CH592蓝牙主机(Central)实战指南:TMOS任务间高效通信与数据传递

1. TMOS任务系统基础解析 第一次接触CH57x系列蓝牙开发时,我被TMOS这个名词搞得一头雾水。这玩意儿既不像FreeRTOS有明确的任务切换机制,也不像裸机程序那样直接了当。后来在调试智能家居遥控器项目时,我才真正理解了它的设计哲学——本质上是…...

F5负载均衡+Horizon避坑指南:当云桌面卡顿遇上连接数陷阱

F5负载均衡Horizon避坑指南:当云桌面卡顿遇上连接数陷阱 混合云架构中,VMware Horizon虚拟桌面与F5负载均衡器的组合已成为企业标准化部署方案。但当用户频繁报告"画面卡顿""鼠标漂移"等玄学问题时,真正的罪魁祸首往往隐…...

如何快速掌握多光谱目标检测:跨模态融合技术的终极指南

如何快速掌握多光谱目标检测:跨模态融合技术的终极指南 【免费下载链接】multispectral-object-detection Multispectral Object Detection with Yolov5 and Transformer 项目地址: https://gitcode.com/gh_mirrors/mu/multispectral-object-detection 多光谱…...

法律AI的资源革命:ChatLaw2-MoE模型的高效训练与实践指南

法律AI的资源革命:ChatLaw2-MoE模型的高效训练与实践指南 【免费下载链接】ChatLaw 中文法律大模型 项目地址: https://gitcode.com/gh_mirrors/ch/ChatLaw 一、问题:法律大模型的资源困境与突破方向 法律人工智能领域正面临一个严峻的资源悖论&…...

Spring AI 整合 Google Gemini 2.5 Pro 保姆级教程(含免费额度说明)

Spring AI 整合 Google Gemini 2.5 Pro 实战指南 引言 在当今快速发展的AI领域,Google Gemini系列模型以其强大的多模态能力和灵活的API接口,成为开发者关注的焦点。特别是Gemini 2.5 Pro版本,在保持高性能的同时提供了相对友好的免费额度&…...

autofit.js vs 传统响应式:哪种屏幕适配方案更适合你的项目?

autofit.js与传统响应式方案深度对比:如何选择最佳屏幕适配策略 在当今多终端设备并存的互联网环境中,屏幕适配已成为前端开发无法回避的核心挑战。从4K显示器到折叠屏手机,从平板电脑到智能电视,开发者需要确保界面在各种分辨率下…...

模电之直流可调稳压电源设计:Multisim14仿真探索

模电 直流可调稳压电源设计 Multisim14 仿真报告 利用三极管、二极管基本特性,稳压电源知识设计相应模拟电路。 (1)用集成芯片制作一个0~15V的直流电源; (2)功率≥12W; (3&#xf…...

UniApp地图开发实战:如何用透明图+cover-view实现动态标记点高级定制(附完整代码)

UniApp地图开发实战:透明图与cover-view实现动态标记点高级定制 在移动应用开发中,地图功能已经成为许多应用的核心组件。无论是外卖配送、共享出行还是社交应用,都需要在地图上展示动态变化的标记点。UniApp作为跨平台开发框架,其…...

Yi-Coder-1.5B教学应用:编程习题自动生成与评判系统

Yi-Coder-1.5B教学应用:编程习题自动生成与评判系统 1. 引言 编程教学中最头疼的事情是什么?不是学生听不懂理论,而是缺乏足够的练习题目和及时的反馈。传统的编程教学往往受限于教师精力,无法为每个学生提供个性化的练习和详细…...

Simplorer与Maxwell电机联合仿真:开启电机仿真新世界

Simplorer与Maxwell电机联合仿真,包含搭建好的Simplorer电机场路耦合主电路与控制算法(矢量控制SVPWM),包含电路与算法搭建的详细教,程视,频。 仿真文件可复制,可将教程中的电机模型换成自己的电…...

SystemVerilog功能覆盖率实战:cover group与coverpoint的5个常见坑点解析

SystemVerilog功能覆盖率实战:cover group与coverpoint的5个常见坑点解析 在芯片验证领域,功能覆盖率是衡量验证完备性的黄金标准。不同于代码覆盖率仅反映代码执行情况,功能覆盖率直接映射设计规格,是验证工程师手中的"探测…...

若依框架下JimuReport积木报表的Token安全集成实践

1. 若依框架与JimuReport积木报表的Token集成背景 在企业级应用开发中,报表系统往往是核心功能模块之一。JimuReport积木报表作为一款开源的报表工具,以其灵活性和易用性受到开发者青睐。而若依(RuoYi)框架则是一个基于Spring Boo…...

LeagueAkari:英雄联盟玩家的智能效率助手

LeagueAkari:英雄联盟玩家的智能效率助手 【免费下载链接】LeagueAkari ✨兴趣使然的,功能全面的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/LeagueAkari 还在为英雄联盟繁琐的…...

Docker挂载卷修改实战:3种方法解决路径变更难题(附详细步骤)

Docker挂载卷路径变更的实战指南:3种高效解决方案 每次项目结构调整时,最让我头疼的就是那些已经配置好的Docker挂载卷路径。上周迁移服务器时,我不得不面对十几个容器挂载路径的调整问题。经过反复尝试和踩坑,我总结出三种最实用…...

Windows服务器上的加密狗怎么共享给家里电脑用?保姆级配置USB Redirector和cpolar教程

专业软件加密狗远程共享全攻略:基于USB Redirector与cpolar的实战方案 1. 加密狗远程共享的核心价值与场景痛点 对于依赖专业软件的设计师、工程师和开发人员来说,软件加密狗往往是价值数万元的正版授权核心载体。传统工作模式下,这些物理加…...

从“厨房”到“餐厅”:用生活场景拆解CUDA、cuDNN与PyTorch的协作关系

1. 当深度学习遇上厨房:一场技术盛宴的幕后故事 想象一下你走进一家米其林餐厅,品尝到一道令人惊艳的料理。这背后需要什么?一个设备齐全的厨房、一套顺手的厨具、一把锋利的刀具,还有一份精心设计的菜谱。深度学习的世界也是如此…...

2024移动端UI设计趋势:除了深色模式,这些新规范你必须知道

2024移动端UI设计趋势:超越深色模式的五大革新方向 当设计师们还在为深色模式的适配问题焦头烂额时,移动界面设计的前沿已经悄然进化。Material Design 3和iOS 17带来的不仅是视觉语言的更新,更是一场关于人机交互本质的重新思考。从折叠屏的…...

UniGUI界面太单调?试试这个技巧:把Figma炫酷的按钮和卡片样式‘偷’过来

UniGUI界面改造实战:从Figma精准移植现代CSS样式 每次打开UniGUI项目,看到那些仿佛停留在2005年的默认控件样式,是不是有种想砸键盘的冲动?作为开发者,我们当然知道功能才是核心,但用户第一眼看到的永远是…...

Photoshop与EasyX结合:高效生成掩码图实现游戏透明贴图

1. 为什么游戏开发需要透明贴图技术 在开发2D小游戏时,角色和背景的融合是个常见需求。想象一下,如果你的游戏角色总是带着一个难看的白色矩形背景,那画面简直就像是从Windows 98时代穿越过来的。我刚开始做游戏时就犯过这个错误,…...

Innovus实战:如何用一条命令自动清理postRoute阶段冗余的PHC hold buffer?

Innovus实战:一键清理postRoute阶段冗余PHC hold buffer的高效方法 在数字IC后端设计的最后阶段,工程师们常常面临一个棘手问题:那些在postCTS阶段为修复hold违例而大量插入的PHC hold buffer,在完成布线后变得冗余,却…...