告别MyBatis的‘?‘占位符:用p6spy 3.9.1在Spring Boot里打印可直接执行的SQL(附自定义日志格式)

张开发
2026/4/20 3:52:26 15 分钟阅读
告别MyBatis的‘?‘占位符:用p6spy 3.9.1在Spring Boot里打印可直接执行的SQL(附自定义日志格式)
告别MyBatis的?占位符用p6spy 3.9.1在Spring Boot里打印可直接执行的SQL附自定义日志格式调试SQL语句是Java开发中的日常操作但MyBatis和JPA等ORM框架输出的预编译SQL总带着恼人的?占位符。每次排查问题时开发者不得不手动替换参数既浪费时间又容易出错。p6spy 3.9.1正是为解决这一痛点而生——它能将晦涩的预编译语句转换为可直接在数据库客户端执行的完整SQL。1. 为什么需要SQL语句可视化在Spring Boot项目中ORM框架生成的SQL日志通常是这样的SELECT * FROM users WHERE id ? AND status ?这种输出对调试极不友好无法直接执行需要手动替换占位符缺少关键信息执行时间、连接ID等调试要素缺失上下文割裂难以关联同一事务中的多条SQLp6spy通过数据源代理技术在SQL到达真实数据库前进行拦截和格式化。相比原生HikariCP或Druid的监控功能它的优势在于完整的参数替换自动将?替换为实际值执行耗时统计精确到毫秒的性能数据多输出渠道控制台、文件或Slf4j日志系统实际项目中使用p6spy后SQL日志变为[2023-08-20 14:30:45] --- | took 12ms | statement | connection 5 SELECT * FROM users WHERE id 123 AND status ACTIVE;2. Spring Boot集成实战2.1 依赖配置首先在pom.xml中添加p6spy依赖注意排除可能冲突的旧版本dependency groupIdp6spy/groupId artifactIdp6spy/artifactId version3.9.1/version /dependency2.2 数据源改造修改application.yml中的数据库配置spring: datasource: driver-class-name: com.p6spy.engine.spy.P6SpyDriver url: jdbc:p6spy:mysql://localhost:3306/db_name # 原始配置需保留在spy.properties中2.3 核心配置文件在resources/spy.properties中配置基础参数# 启用SQL格式化模块 module.logcom.p6spy.engine.logging.P6LogFactory # 使用控制台输出 appendercom.p6spy.engine.spy.appender.StdoutLogger # 真实数据库驱动 driverlistcom.mysql.cj.jdbc.Driver # 慢SQL阈值(秒) outagedetectiontrue outagedetectioninterval23. 高级格式化技巧3.1 内置格式化方案p6spy提供两种预置格式SingleLineFormat默认基础单行输出CustomLineFormat可配置的模板化输出推荐使用CustomLineFormat并配置logMessageFormatcom.p6spy.engine.spy.appender.CustomLineFormat customLogMessageFormat%(currentTime) | 耗时 %(executionTime)ms | 连接 %(connectionId) | 语句%(sql)3.2 自定义格式化器创建自定义格式化类实现更复杂的日志输出public class CustomSqlFormatter implements MessageFormattingStrategy { Override public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql) { return String.format(\n[%s] [%dms] %s\n%s;, LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME), elapsed, category, sql.replaceAll(\\s, ).trim()); } }然后在配置中指定logMessageFormatcom.your.package.CustomSqlFormatter4. 生产环境最佳实践4.1 性能优化配置# 关闭不必要的信息 excludecategoriesinfo,debug,resultset,batch # 仅记录超过100ms的SQL executionThreshold100 # 异步日志输出需配合Log4j2 appendercom.p6spy.engine.spy.appender.AsyncLogger4.2 多环境策略建议通过Spring Profile实现差异化配置# application-dev.yml p6spy: enabled: true log-level: debug # application-prod.yml p6spy: enabled: false4.3 与Logback集成对于使用SLF4J的项目推荐配置appendercom.p6spy.engine.spy.appender.Slf4JLogger logMessageFormatcom.p6spy.engine.spy.appender.CustomLineFormat customLogMessageFormat[%(executionTime)ms] %(sqlSingleLine)配合logback-spring.xml实现SQL日志单独归档appender nameSQL_APPENDER classch.qos.logback.core.rolling.RollingFileAppender filelogs/sql.log/file filter classch.qos.logback.classic.filter.ThresholdFilter levelDEBUG/level /filter /appender logger namep6spy levelDEBUG additivityfalse appender-ref refSQL_APPENDER/ /logger5. 疑难问题排查问题1SQL日志没有参数替换检查driverlist是否配置了真实驱动确认URL前缀为jdbc:p6spy:问题2性能明显下降启用executionThreshold过滤短耗时SQL考虑使用AsyncLogger异步输出问题3与HikariCP兼容问题# 在spy.properties中添加 deregisterdriverstrue realdatasourceclasscom.zaxxer.hikari.HikariDataSource在最近的一个电商项目中我们通过p6spy发现了多个N1查询问题。其中一个商品列表接口的SQL调用次数从原来的57次降到了3次响应时间从1200ms优化到200ms。关键就在于能直观看到完整SQL执行序列。

更多文章