mybatis拦截器通过同时拦截executor和statementhandler实现慢查询告警与性能分析:前者统计执行耗时,后者提取归一化sql;结合动态阈值、异步告警、执行计划采集与分级推送,形成轻量级全链路诊断方案。

MyBatis 的拦截器(Interceptor)机制是实现 SQL 慢查询告警与自动性能分析的轻量级、侵入性低的方案。核心在于拦截 StatementHandler 的 prepare 方法获取原始 SQL,再在 Executor 的 query/update 方法前后记录执行耗时,结合阈值判断是否触发告警与分析。
拦截关键执行节点并统计耗时
需同时拦截 Executor 和 StatementHandler 两个对象:前者负责实际执行(含事务、缓存逻辑),后者封装 SQL 编译与参数绑定。仅拦截 Executor#query 和 Executor#update 即可覆盖所有 DML/DDL 操作;StatementHandler#prepare 可提取未填充参数的 SQL 模板,用于后续归类与脱敏。
- 在
intercept()中用System.nanoTime()记录开始时间,执行目标方法后计算耗时(纳秒转毫秒) - 避免在事务回滚或异常抛出时漏统计——建议在
try-finally中完成耗时采集,而非仅依赖正常返回路径 - 对批量操作(如
foreach批量插入)注意单条 SQL 耗时 vs 整体批次耗时,建议按单条语句粒度统计
SQL 归一化与慢查询判定
直接比对原始 SQL 易受参数干扰(如 WHERE id = 123 和 WHERE id = 456 被视为不同),需做归一化处理:替换字面量为占位符(如 ? 或 ##VALUE##),保留表名、字段、关键词结构。再与预设阈值(如 500ms)比较,超时即标记为慢查询。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 使用正则或 AST 解析(如 JSqlParser)实现安全归一化;简单场景可用
replaceAll("(?i)'[^']*'|\d+", "?")粗略脱敏 - 阈值支持动态配置(如从 Apollo/Nacos 加载),避免硬编码;可按数据库类型(MySQL/Oracle)、环境(prod/test)差异化设置
- 同一 SQL 模板在单位时间内高频超时(如 1 分钟内 5 次 >1s),应升级为“持续性慢 SQL”并触发更高级告警
自动采集执行计划与上下文信息
慢查询告警不应只报“某 SQL 慢”,而要附带可诊断线索。拦截器可在检测到慢查询后,自动执行 EXPLAIN(MySQL)或 EXPLAIN PLAN(Oracle),并将结果连同调用栈、Mapper 接口名、参数摘要、连接池活跃数等一并收集。
- 通过
MappedStatement获取mapperInterface和method名,定位具体业务代码位置 - 从
BoundSql提取参数映射,对敏感字段(如手机号、身份证号)做掩码处理(如138****1234) - 借助
DataSource获取当前连接的数据库 URL 和用户名,辅助排查库级别瓶颈(如主从延迟、读写分离路由异常)
异步告警与分级推送策略
告警逻辑必须异步执行,防止拖慢主业务线程。建议将慢查询事件投递至内存队列(如 BlockingQueue)或消息中间件(如 RocketMQ),由独立消费者处理推送、聚合、抑制和归档。
- 按严重程度分级:普通慢查(>500ms)企业微信/钉钉文本通知;严重慢查(>5s 或全表扫描)电话+邮件双通道
- 同一 SQL 模板 10 分钟内重复告警自动合并,避免刷屏;支持按应用名、模块、负责人标签路由告警
- 将分析结果写入日志中心(如 ELK)或时序数据库(如 Prometheus + Grafana),提供慢 SQL TOP N、趋势图、平均耗时下钻能力
不复杂但容易忽略:拦截器注册顺序影响行为(如分页插件、租户插件可能修改 SQL),务必确保慢查拦截器在最外层;同时注意多数据源场景下,每个 SqlSessionFactory 都需单独注册拦截器。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










