核心是分层埋点:框架层用aop切mapper方法精准计时并提取脱敏sql;驱动层用p6spy零代码代理监控慢sql;字节码增强实现无侵入全链路追踪与超时熔断。

Java 中监控 JDBC SQL 执行耗时与性能,核心在于“在合适的位置埋点、以低侵入方式捕获真实执行时间、兼顾准确性与可观测性”。不推荐手动在每个 JdbcTemplate 或 PreparedStatement 前后加 System.nanoTime(),那样维护成本高、易遗漏、无法覆盖框架内部调用。真正实用的方案分三层:框架层拦截、驱动层代理、字节码增强。
用 AOP 在 Mapper/DAO 层切面监控(适合 MyBatis/MyBatis-Plus)
这是语义最清晰、改造最小、效果最稳的方式:
- 切点定义为
execution(* com.xxx.mapper..*Mapper.*(..)),精准命中数据访问入口 - 环绕通知中用
System.nanoTime()记录起止时间,避免Instant.now()的时钟开销 - 执行完
proceed()后,若耗时超阈值(如 300ms),提取BoundSql.getSql()和参数(通过DefaultParameterHandler渲染,注意脱敏手机号、身份证等字段) - 日志中带上
MDC.get("traceId")、线程名、简单堆栈(前 3 层),便于链路对齐
用 p6spy 或 log4jdbc 做 JDBC 驱动代理(零代码修改)
无需改业务,只需替换驱动和配置,适合快速上线或临时诊断:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- p6spy:数据库 URL 改为
jdbc:p6spy:mysql://...,spy.properties中设executionThreshold=300即可自动标出慢 SQL;支持参数记录、SQL 格式化,但生产建议关闭参数采集以防敏感泄露 - log4jdbc:原理类似,通过
StatementSpy包装原始 Statement,在execute方法前后打点,日志级别设为DEBUG即可看到带毫秒的 SQL 行:12:34:56.789 [main] DEBUG jdbc.sqltiming - SELECT * FROM user WHERE id=? {executed in 423 ms} - 两者都增加约 5%~10% CPU 开销,压测环境可用,生产环境建议仅开启慢 SQL 监控
用 javaagent 字节码增强(无侵入、全链路、可强制熔断)
适用于对稳定性要求极高、需统一管控所有 JDBC 调用的中大型系统:
- 通过
Instrumentation在类加载时重写PreparedStatement#execute*、Statement#execute*等方法字节码,插入计时逻辑 - 可结合
ThreadLocal存储上下文(如事务 ID、用户 ID),实现跨方法的 SQL 耗时归因 - 不止于记录——还能在超时(如 5s)时主动中断执行,抛出
SQLException防止拖垮连接池 - 典型实现如自研探针或商业 APM(SkyWalking JDBC 插件、Pinpoint 的 JDBC 拦截器)
补充:Spring Boot 内置 + MyBatis-Plus 性能插件(开发期友好)
适合本地调试和测试环境快速验证:
- MyBatis-Plus 的
PerformanceInterceptor:配置maxTime=1000和format=true,控制台直接输出带格式的 SQL 和耗时,超时自动 WARN - Spring Boot Actuator +
DataSourcePoolMetadata:暴露连接池活跃数、等待数、平均获取连接时间,间接反映 JDBC 层压力 - 注意:这些插件默认不记录真实 SQL 参数,也不适配复杂嵌套事务,不能替代生产级监控
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










