MyBatis插件开发实现SQL执行耗时监控
MyBatis插件通过拦截器机制实现SQL执行耗时监控,核心是拦截StatementHandler或Executor相关方法,记录执行前后时间差。
创建自定义拦截器类
自定义拦截器需实现Interceptor接口,添加@Intercepts注解定义拦截目标。以下示例拦截StatementHandler的query和update方法:
java
@Intercepts({
@Signature(type = StatementHandler.class, method = "query",
args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update",
args = {Statement.class})
})
public class SqlCostInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = invocation.proceed();
long endTime = System.currentTimeMillis();
System.out.println("SQL执行耗时: " + (endTime - startTime) + "ms");
return result;
}
}
注册拦截器到MyBatis配置
在MyBatis配置文件中添加拦截器,或通过编程方式注册:
XML
<plugins>
<plugin interceptor="com.example.SqlCostInterceptor"/>
</plugins>
或通过SqlSessionFactory配置:
java
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setPlugins(new SqlCostInterceptor());
return factory.getObject();
}
增强监控信息输出
可通过MappedStatement获取SQL详细信息,完善监控日志:
java
StatementHandler handler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = handler.getBoundSql();
MappedStatement ms = (MappedStatement)
ReflectUtil.getFieldValue(handler, "mappedStatement");
String sqlId = ms.getId();
String sql = boundSql.getSql();
使用SLF4J记录日志
推荐整合日志框架替代System.out:
java
private static final Logger logger = LoggerFactory.getLogger(SqlCostInterceptor.class);
// 在intercept方法中记录
logger.debug("SQL [{}]执行耗时: {}ms", sqlId, (endTime - startTime));
注意事项
拦截器顺序可能影响执行结果,需通过@Order注解或配置顺序控制。避免在拦截器中执行耗时操作,防止性能影响。生产环境建议添加阈值报警机制,对慢SQL进行标记。