ibatis中SQL查询耗时监控拦截器

1、定义拦截器


@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
@Slf4j
public class SlowQueryInterceptor implements Interceptor {
    private long queryTimeThreshold;

    // 设置慢查询的时间阈值
    public void setQueryTimeThreshold(long queryTimeThreshold) {
        this.queryTimeThreshold = queryTimeThreshold;
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameter = null;
        if (invocation.getArgs().length > 1) {
            parameter = invocation.getArgs()[1];
        }
        long start = System.currentTimeMillis();
        try {
            return invocation.proceed();
        } finally {
            long end = System.currentTimeMillis();
            long executeTime = end - start;
            if (executeTime > queryTimeThreshold) {
                // 记录慢查询日志
                logSlowQuery(mappedStatement, parameter, executeTime);
            }
        }
    }

    private void logSlowQuery(MappedStatement ms, Object parameter, long time) {
        log.info("-----------------------------------------------------------------");
        log.info("查询耗时:" + time +",SQL: "+ms.getBoundSql(parameter).getSql());
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

}

二、注册拦截器

@Configuration
public class FrameMyBatisPluginConfig {

    //SQL查询耗时时间设置,超过则打印sql
    @Value("${sql.execute.over.time.for.print:4000}")
    private long overTime;

    @Bean
    public String SQLTableNameHandleInterceptor(SqlSessionFactory sqlSessionFactory) {
        //实例化插件
        SlowQueryInterceptor slowQueryInterceptor = new SlowQueryInterceptor();

        //将属性值设置到插件中
        slowQueryInterceptor.setQueryTimeThreshold(overTime);
        //将插件添加到SqlSessionFactory工厂
        sqlSessionFactory.getConfiguration().addInterceptor(slowQueryInterceptor);
        return "interceptor";
    }
}

三、日志效果
在这里插入图片描述

### MyBatis 拦截器的使用与实现 #### 什么是 MyBatis 拦截器? MyBatis 提供了一种灵活的方式来扩展其功能——拦截器(Interceptor)。它允许开发人员在 SQL 执行的不同阶段插入自定义逻辑。通过拦截器,可以对 ParameterHandler、StatementHandler、Executor 和 ResultSetHandler 这四种类型的对象进行拦截并修改它们的行为[^1]。 --- #### 截获的目标接口 MyBatis 的拦截器能够拦截以下四个核心接口中的方法调用: - **`org.apache.ibatis.executor.Executor`**: 主要用于拦截执行器的相关操作,比如 `update()` 或 `query()` 方法。 - **`org.apache.ibatis.executor.statement.StatementHandler`**: 负责处理 SQL 语句的构建和预编译工作。 - **`org.apache.ibatis.executor.parameter.ParameterHandler`**: 处理 SQL 参数绑定的过程。 - **`org.apache.ibatis.executor.resultset.ResultSetHandler`**: 对查询结果集进行解析的操作[^3]。 这些目标接口覆盖了 MyBatis 数据访问的核心流程,使得开发者可以在多个层次上定制化行为。 --- #### 如何创建一个简单的 MyBatis 拦截器? 下面展示了一个基本的拦截器实现: ```java import org.apache.ibatis.plugin.*; import java.util.Properties; @Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) }) public class ExampleInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println("Before update operation..."); Object result = invocation.proceed(); // 继续执行原生方法 System.out.println("After update operation..."); return result; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); // 将当前拦截器应用到目标对象 } @Override public void setProperties(Properties properties) { // 可在此设置一些属性配置 } } ``` 上述代码展示了如何编写一个拦截器来捕获 `Executor.update()` 方法的调用,并在其前后打印日志消息[^4]。 --- #### 配置拦截器的方式 ##### 方式一:XML 配置方式 如果未启用 Spring 容器管理,则可以通过 XML 文件注册拦截器: ```xml <plugins> <plugin interceptor="com.example.ExampleInterceptor"/> </plugins> ``` ##### 方式二:Spring 自动扫描 当项目基于 Spring Boot 构建时,可以直接将拦截器声明为 Bean 并交由框架托管。只需给拦截器类加上 `@Component` 注解即可自动加载: ```java @Component public class ExampleInterceptor implements Interceptor { ... } ``` 这种方式下无需手动配置插件实例,因为 Spring 会在初始化过程中完成注入。 --- #### 实际应用场景举例 以下是几个常见的场景及其对应的解决方案说明: 1. **分页查询** - 使用拦截器动态改写 SQL 查询语句,在原有基础上附加 LIMIT 子句以支持分页功能[^2]。 2. **性能监控** - 在 StatementHandler 层面记录每条 SQL耗时情况,便于后续分析优化瓶颈所在。 3. **多租户隔离** - 动态向所有 SELECT/UPDATE/DML 类型的 SQL 中追加特定条件字段(如 TenantId),从而保障跨账户间的数据安全边界。 4. **缓存控制** - 借助 Executor 接口重载部分更新逻辑,减少不必要的数据库交互次数;或者引入第三方分布式缓存组件作为补充存储介质。 --- #### 注意事项 尽管拦截器提供了强大的能力,但在设计时仍需注意以下几点原则: - 不应过度依赖于拦截器解决复杂业务需求; - 修改原始 SQL 结构可能带来潜在风险,务必充分测试验证兼容性; - 如果涉及事务上下文中敏感数据变更,请格外小心避免破坏一致性约束。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值