JDBC 本身不提供耗时日志,需在SQL执行前后埋点计时;推荐P6Spy零代码接入,其次Spring AOP切面、Druid Filter或手写代理实现。

Java 中 JDBC 本身不提供执行耗时日志功能,必须通过拦截 SQL 执行过程,在调用前后打时间戳并计算差值。关键不是“加日志”,而是“在正确位置埋点”,同时兼顾准确性、可读性和生产安全性。
用 P6Spy 零代码接入(推荐上线首选)
无需改业务代码,只需替换驱动和配置,适合快速落地或生产环境长期监控:
- 数据库 URL 改为 jdbc:p6spy:mysql://...(其他数据库同理,如 postgresql、oracle)
- 驱动类改为 com.p6spy.engine.spy.P6SpyDriver
- 在
spy.properties中设置:
executionThreshold=300 —— 只记录超 300ms 的 SQL
logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat —— 输出紧凑格式
includeValues=false —— 生产禁用参数明文(防敏感泄露) - 日志示例:
[327 ms] SELECT * FROM user WHERE id = ?
用 Spring AOP 在 Mapper 层切面(语义最清晰)
适用于 MyBatis/MyBatis-Plus 项目,能精准关联 SQL 与业务方法,天然支持 traceId 和参数脱敏:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 切点写法:
execution(* com.xxx.mapper..*Mapper.*(..)) - 环绕通知中用
System.nanoTime()记录起止时间(比System.currentTimeMillis()更准) - 执行完
proceed()后判断是否超阈值,再提取BoundSql.getSql()和参数 - 参数需脱敏:手机号 →
138****1234,身份证 →110***********123X - 日志带上
MDC.get("traceId")、线程名、DAO 方法签名和简短堆栈(前 3 层)
用 Druid 内置 Filter(已有 Druid 的项目直接启用)
如果你已在用 Druid 连接池,开启 StatFilter + LogFilter 即可获得结构化执行日志:
立即学习“Java免费学习笔记(深入)”;
- 配置
filters: stat,logback(Logback 环境)或stat,log4j2 - 设
slowSqlMillis=100、logSlowSql=true - 在
logback-spring.xml中显式开启 DEBUG 级别:
<logger name="druid.sql.Statement" level="DEBUG" /> - 效果:每条 SQL 日志含连接 ID、预编译 ID、真实 SQL、耗时、影响行数、异常标记等
手写代理或工具类(适合学习或轻量定制)
不依赖框架,适合理解原理或嵌入自研连接池场景:
- JDK 动态代理包装
PreparedStatement,在executeQuery()等方法前后记纳秒时间 - 捕获异常时也记录耗时,并标注 “FAILED”
- 或封装静态工具方法如
JdbcUtils.queryWithTime(connection, sql, params),显式包裹执行逻辑 - 注意:SQL 参数填充需自行实现(如用
String.format或ParameterMetaData),生产慎用未脱敏的完整 SQL

















