在线程池内捕获SlowSQL,本质是将SQL执行逻辑封装于自定义任务中,在executeQuery()等真实执行点前后统计耗时并记录日志,而非监控线程池调度过程;推荐用装饰器模式封装JDBC/MyBatis调用,并结合AOP实现无感增强。

Java在线程池内部捕获并记录SlowSQL,本质不是“在线程池里做SQL监控”,而是把SQL执行逻辑(如JDBC调用、MyBatis操作)放在自定义线程池任务中执行,并在任务执行前后加耗时统计与条件日志。关键在于监控点必须落在SQL真正执行的位置,而非线程池提交或获取阶段。
明确监控边界:线程池本身不执行SQL
线程池(如ThreadPoolExecutor)只负责调度Runnable/Callable任务。如果任务里是纯业务逻辑(比如计算、组装参数),没碰数据库,那再慢也跟SQL无关。真正执行SQL的是:
- JDBC的
PreparedStatement#executeQuery()或executeUpdate() - MyBatis的
SqlSession#selectList()等方法 - JPA的
EntityManager#find()或原生查询
所以“在线程池内捕获SlowSQL”,实际是指:把含SQL操作的任务提交给线程池,并在该任务内部完成SQL耗时测量与日志记录。
推荐做法:用装饰器模式封装SQL执行逻辑
不侵入业务代码,也不依赖全局拦截器(如MyBatis Interceptor),适合异步任务场景。示例(以JDBC为例):
定义一个带耗时审计的JDBC执行器:
public class AuditableJdbcExecutor {
private static final long SLOW_THRESHOLD_MS = 500L;
private final Logger auditLogger = LoggerFactory.getLogger("SLOW_SQL_AUDIT");
<pre class="brush:php;toolbar:false;">public <t> T execute(String sql, Supplier<t> statementAction) {
long start = System.nanoTime();
try {
return statementAction.get();
} finally {
long costMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
if (costMs >= SLOW_THRESHOLD_MS) {
auditLogger.warn("Slow SQL detected [{}ms]: {}", costMs, sql);
// 可扩展:记录线程名、上下文traceId、参数占位符替换值等
}
}
}</t></t>}
在线程池任务中使用:
executor.submit(() -> {
String sql = "SELECT * FROM order WHERE user_id = ? AND status = ?";
List<order> orders = auditableExecutor.execute(sql, () -> {
// 真正的JDBC执行逻辑(含参数设置、查询)
return jdbcTemplate.query(sql, rowMapper, userId, status);
});
});</order>
结合Spring AOP实现无感增强(适用于@Async方法)
若异步方法由@Async驱动,可对这些方法切面织入SQL审计逻辑:
- 定义切点:匹配
@Async标注且含SQL操作的方法(如方法名含"Query"、"Find"、"Count") - 在
@Around通知中启动计时,方法返回前判断是否超阈值 - 通过
ThreadLocal传递当前任务ID或traceId,确保日志可追溯
注意:AOP无法直接拿到SQL文本,需配合MyBatis的BoundSql提取,或要求业务方法显式传入SQL模板作为参数。
避坑提醒:别在submit()或execute()上计时
以下写法是错误的:
// ❌ 错误:只测了“提交”耗时,不是SQL执行耗时
long start = System.currentTimeMillis();
executor.submit(runnable);
log.info("submit cost: {}ms", System.currentTimeMillis() - start);
真正要测的是SQL在数据库里跑的时间,必须包裹在run()或call()内部。另外,避免在日志中直接拼接完整SQL(尤其含敏感字段),应脱敏或仅记录模板+参数类型。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











