跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

MyBatis 全局性能监控拦截器实战指南

本文介绍如何通过 mybatis 插件机制实现轻量级、无侵入的全局 sql 执行性能监听,自动捕获超时查询与高负载操作,并支持毫秒级响应时间统计和结果集规模预警。 本文介绍如何通过 mybatis 插件机制实现轻量级、无侵入的全局 sql 执行性能监听,自动捕获超时查询与高负载操作,并支持毫秒级响应时间统计和结果集规模预警。 在企业级 Java 应用中,数据库性能往往是系统瓶颈的关键来源。MyBatis 作为主流持久层框架,其 SQL 执行效率直接影响整体 QoS(服务质量)。为实现“零改造业务代码”的性能可观测性,推荐采用 MyBatis Interceptor(插件)机制 ——它基于 JDK 动态代理,在 Executor 层统一拦截所有 query 和 update 操作,无需修改 Mapper 接口或 Service 层逻辑。 以下是一个生产就绪的性能监听拦截器示例,不仅统计执行耗时,还可扩展支持结果集大小预警:
import java.text.MessageFormat; import java.util.List; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; @Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) }) public class PerformanceMonitoringInterceptor implements Interceptor { private static final Log log = LogFactory.getLog(PerformanceMonitoringInterceptor.class); // 可配置阈值(单位:纳秒),建议默认设为 100_000_000L ≈ 100ms private long thresholdNanos = 100_000_000L; // 结果集行数预警阈值(仅对 query 生效) private int resultSizeThreshold = 1000; @Override public Object intercept(Invocation invocation) throws Throwable { long start = System.nanoTime(); Object result = invocation.proceed(); long duration = System.nanoTime() - start; MappedStatement ms = (MappedStatement) invocation.getArgs()[0]; String statementId = ms.getId(); // 耗时告警(DEBUG 级别日志,避免线上性能损耗) if (log.isDebugEnabled() && duration > thresholdNanos) { log.debug(MessageFormat.format( "[PERF-WARN] Statement '{0}' took {1, number,###} ms (threshold: {2, number,###} ms)", statementId, duration / 1_000_000.0, thresholdNanos / 1_000_000.0)); } // 结果集规模预警(仅对查询且返回 List 的场景) if (result instanceof List list && list.size() > resultSizeThreshold) { log.warn(MessageFormat.format( "[DATA-WARN] Statement '{0}' returned {1} rows (threshold: {2})", statementId, list.size(), resultSizeThreshold)); } return result; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { String threshold = properties.getProperty("thresholdMillis", "100"); this.thresholdNanos = Long.parseLong(threshold) * 1_000_000L; String sizeThreshold = properties.getProperty("resultSizeThreshold", "1000"); this.resultSizeThreshold = Integer.parseInt(sizeThreshold); } }
✅ 关键特性说明: ✅ 双维度监控 :同时支持「执行耗时」与「结果集规模」双阈值预警; ✅ 零侵入集成 :不依赖 Spring AOP 或字节码增强,完全兼容原生 MyBatis 与 mybatis-spring-boot-starter; ✅ 可配置化 :通过 setProperties() 支持 XML 或 @ConfigurationProperties 动态注入阈值; ✅ 日志分级控制 :耗时日志使用 DEBUG 级别,线上可关闭;严重超限/大数据量使用 WARN,确保可追溯。 ? 注册方式(任选其一): XML 配置(mybatis-config.xml) :
Spring Boot 自动装配(推荐) :
@Configuration public class MyBatisConfig { @Bean public Interceptor performanceMonitor() { PerformanceMonitoringInterceptor interceptor = new PerformanceMonitoringInterceptor(); Properties props = new Properties(); props.setProperty("thresholdMillis", "50"); props.setProperty("resultSizeThreshold", "500"); interceptor.setProperties(props); return interceptor; } }
⚠️ 注意事项: 避免在 intercept() 中执行耗时操作(如远程调用、复杂计算),否则会污染原始性能指标; System.nanoTime() 是最精准的计时方式,优于 System.currentTimeMillis(); 若需采集更丰富指标(如 SQL 参数、慢 SQL 样本、调用堆栈),建议结合 Micrometer + Prometheus 或接入 SkyWalking 等 APM 工具; 生产环境务必关闭 DEBUG 日志,或通过日志门控(如 Logback 的 ThresholdFilter)限制性能日志输出频率。 通过该拦截器,你可在 5 分钟内为整个 MyBatis 应用装上“性能雷达”,快速识别慢 SQL、N+1 查询及数据膨胀风险,真正实现质量左移与主动式运维。

相关文章