当前位置: 首页 > news >正文

31. 如何在MyBatis中使用自定义拦截器?有哪些常见应用场景?

在 MyBatis 中,自定义拦截器是一个强大的功能,允许开发者在 SQL 语句执行的不同阶段进行拦截、修改或扩展操作。拦截器可以用于日志记录、性能监控、权限检查等多种场景。MyBatis 提供了 Interceptor 接口来实现自定义拦截器。

如何在 MyBatis 中使用自定义拦截器?

1. 实现 Interceptor 接口

要创建一个自定义拦截器,首先需要实现 MyBatis 的 Interceptor 接口。这个接口有一个 intercept 方法,负责处理拦截的逻辑。

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
​
import java.sql.Connection;
import java.util.Properties;
​
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyCustomInterceptor implements Interceptor {
​@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 在这里添加拦截逻辑StatementHandler statementHandler = (StatementHandler) invocation.getTarget();String sql = statementHandler.getBoundSql().getSql();System.out.println("Executing SQL: " + sql);// 调用原方法return invocation.proceed();}
​@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}
​@Overridepublic void setProperties(Properties properties) {// 设置拦截器的属性}
}

2. 配置拦截器

实现拦截器之后,需要在 MyBatis 配置文件中注册这个拦截器。

XML 配置

<configuration><plugins><plugin interceptor="com.example.MyCustomInterceptor"><!-- 可以在这里传递自定义属性 --><property name="property1" value="value1"/></plugin></plugins>
</configuration>

Java 配置(如果使用 Spring):

@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);
​// 注册自定义拦截器MyCustomInterceptor interceptor = new MyCustomInterceptor();sessionFactory.setPlugins(new Interceptor[]{interceptor});
​return sessionFactory.getObject();
}

3. 使用拦截器

在你配置了拦截器后,MyBatis 会在执行 SQL 语句的过程中自动调用拦截器。根据拦截器的配置,它会在不同的执行阶段进行干预,例如 SQL 语句准备阶段、执行阶段、结果处理阶段等。

常见应用场景

自定义拦截器在 MyBatis 中有广泛的应用场景,以下是几个常见的应用:

1. SQL 日志记录

可以使用拦截器记录每次执行的 SQL 语句以及执行时间。这对于性能调优和问题排查非常有帮助。

示例

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class SqlLoggerInterceptor implements Interceptor {
​@Overridepublic Object intercept(Invocation invocation) throws Throwable {long startTime = System.currentTimeMillis();
​StatementHandler statementHandler = (StatementHandler) invocation.getTarget();String sql = statementHandler.getBoundSql().getSql();
​try {return invocation.proceed();} finally {long endTime = System.currentTimeMillis();System.out.println("SQL: " + sql + " executed in " + (endTime - startTime) + " ms");}}
​@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}
​@Overridepublic void setProperties(Properties properties) {}
}

2. 数据权限控制

在一些应用中,可能需要在查询或更新数据时,基于用户角色或权限对 SQL 进行过滤或修改。例如,限制某些用户只能查询自己负责的记录。

示例

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class DataPermissionInterceptor implements Interceptor {
​@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();String sql = statementHandler.getBoundSql().getSql();
​// 基于某些条件修改 SQL,比如添加 where 条件限制if (someCondition()) {sql = modifySqlForPermission(sql);Field sqlField = statementHandler.getBoundSql().getClass().getDeclaredField("sql");sqlField.setAccessible(true);sqlField.set(statementHandler.getBoundSql(), sql);}
​return invocation.proceed();}
​private boolean someCondition() {// 检查权限或角色return true;}
​private String modifySqlForPermission(String sql) {// 修改 SQL 以加入权限限制return sql + " AND user_id = 123";}
​@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}
​@Overridepublic void setProperties(Properties properties) {}
}

3. 分页处理

在实现数据库分页功能时,可以通过拦截器自动在 SQL 语句中添加 LIMITOFFSET 子句,避免手动在每个查询中添加分页逻辑。

示例

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class PaginationInterceptor implements Interceptor {
​@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();String sql = statementHandler.getBoundSql().getSql();
​// 添加分页参数int offset = 0;int limit = 10;sql = sql + " LIMIT " + offset + "," + limit;
​Field sqlField = statementHandler.getBoundSql().getClass().getDeclaredField("sql");sqlField.setAccessible(true);sqlField.set(statementHandler.getBoundSql(), sql);
​return invocation.proceed();}
​@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}
​@Overridepublic void setProperties(Properties properties) {}
}

4. 性能监控

拦截器可以用于收集和记录 SQL 执行的时间、次数等信息,帮助进行性能分析和优化。

示例

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class PerformanceMonitoringInterceptor implements Interceptor {
​@Overridepublic Object intercept(Invocation invocation) throws Throwable {long startTime = System.nanoTime();
​Object result = invocation.proceed();
​long endTime = System.nanoTime();System.out.println("SQL executed in " + (endTime - startTime) / 1_000_000 + " ms");
​return result;}
​@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}
​@Overridepublic void setProperties(Properties properties) {}
}

总结

  • 自定义拦截器:在 MyBatis 中,自定义拦截器通过实现 Interceptor 接口来定义拦截逻辑,并通过 @Intercepts 注解来指定要拦截的目标方法。

  • 常见应用场景:SQL 日志记录、数据权限控制、分页处理、性能监控等。

  • 配置拦截器:可以在 MyBatis 配置文件中或通过 Java 代码配置自定义拦截器,以实现对 SQL 执行过程的干预。

通过自定义拦截器,可以在 MyBatis 执行 SQL 的各个阶段插入自定义逻辑,从而实现对数据库操作的灵活控制和扩展。


http://www.mrgr.cn/news/25938.html

相关文章:

  • 显示屏芯片ST7920测试
  • 7-6 列出连通集
  • 递归函数一二
  • HarmonyOS开发实战( Beta5.0)图片编辑实现马赛克效果详解
  • Games101学习 - 光栅化
  • [ IDE ] 什么是SDK
  • vue2关闭eslint
  • 第二证券:再度下挫,贵州茅台盘中失守1300元,五粮液等创阶段新低
  • 重塑在线软件开发新纪元:集成高效安全特性,深度解析与评估支持浏览器在线编程的系统架构设计
  • 高性能编程:无锁队列
  • dngrep(版本 4.2.46.0)里配置用NotePad++打开文件
  • mysql 8.0 时间维度表生成(可运行)
  • SMB流量分析
  • (不用互三)解密AI创作:提升Prompt提示词的提问技巧
  • CSS---序号使用css设置,counter-reset、counter-increment、content配合实现备注文案的序号展示
  • torch.linspace()
  • java spring boot 动态添加 cron(表达式)任务、动态添加停止单个cron任务
  • 猎板PCB大讲堂:PCB设计铺铜技巧与策略全解析
  • 如何编写智能合约——基于长安链的Go语言的合约开发
  • sicp每日一题[2.7]