java慢sql统计核心是执行前后计时并按阈值判定,druid用statfilter零侵入但占位符不替换,mybatis拦截器可还原完整sql并绑定方法,hikaricp需借p6spy或aop实现,须分环境设阈值、脱敏敏感数据、结合上下文综合判断。

Java 中使用连接池的 SQL 拦截器统计慢查询,核心思路是:在 SQL 执行前后打点计时,结合执行耗时阈值做判断,并记录完整 SQL、方法上下文、参数等关键信息。不同连接池实现方式差异较大,下面分主流场景说明。
Druid 连接池内置 StatFilter 方式
Druid 提供开箱即用的 StatFilter,无需写代码即可统计慢 SQL:
- 在 Druid 数据源配置中启用该 Filter:
filters=stat,log4j - 设置慢 SQL 阈值(单位毫秒):
connectionProperties=druid.stat.slowSqlMillis=500 - 开启慢 SQL 日志记录:
druid.stat.logSlowSql=true - 启动后,满足条件的 SQL 会自动输出到日志(如 Log4j),含完整 SQL、执行时间、调用堆栈
优点是零侵入、带 Web 监控页(/druid/sql.html 可查历史慢 SQL);缺点是无法按业务模块分级开关,且 SQL 中的 ? 占位符不会被替换。
MyBatis 自定义拦截器方式
适合需要完整可执行 SQL、绑定方法名、支持动态开关的场景。关键步骤如下:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 实现
org.apache.ibatis.plugin.Interceptor接口,拦截Executor的query/update方法 - 在
intercept()中获取原始 SQL(通过BoundSql.getSql())、参数(parameterObject)、Mapper 方法签名 - 用
ParameterMapping和反射还原真实参数值,拼出完整 SQL(注意处理 null、日期、集合等特殊类型) - 记录开始时间 → 执行原逻辑 → 记录结束时间 → 判断是否超阈值(如 >300ms)→ 写入日志或上报监控系统
这种方式能输出类似:[UserMapper.listActiveUsers] SELECT * FROM user WHERE status = 1 AND create_time > '2026-09-01' —— 耗时 482ms,排查效率高。
HikariCP 需配合其他组件
HikariCP 本身不提供 SQL 拦截能力,但可通过组合方式实现慢 SQL 统计:
- 搭配 P6Spy:替换 JDBC URL 驱动为
p6spy,配置executionThreshold=500即可捕获慢 SQL - 搭配 Spring AOP:切面拦截
JdbcTemplate或MyBatis Mapper接口方法,手动计时+日志 - 搭配 数据库代理层(如 ShardingSphere-JDBC):利用其
SQLLogger或自定义SQLRouteHook做拦截
注意:P6Spy 有轻微性能损耗,生产环境建议只在问题定位期开启;AOP 方式耦合 Spring,但灵活性强。
关键细节提醒
无论选哪种方式,以下三点容易忽略但影响实际效果:
- 阈值要分环境设:开发/测试可设 100ms,预发设 300ms,线上建议 500ms 起步,避免日志刷屏
-
避免记录敏感数据:SQL 中的手机号、身份证号等需脱敏(如正则替换
1[3-9]\d{9}→1****5678) - 慢 SQL 不等于坏 SQL:报表类大查询本就耗时,应结合调用方、QPS、是否定时任务等上下文综合判断,不能只看单次耗时
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










