MyBatis Plus中InnerInterceptor的实现

 更新时间:2025年03月17日 09:22:52   作者:十二同学啊  
本文主要介绍了MyBatis Plus中InnerInterceptor的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在 Spring Boot 项目中使用 MyBatis Plus 时,你可能会遇到 InnerInterceptor 这个概念。 InnerInterceptor 是 MyBatis Plus 提供的一种轻量级 SQL 拦截器,它与传统的 MyBatis 拦截器(Interceptor)有所不同,具有更简单、更高效的特点,并且更专注于 SQL 执行层面的拦截。本文将详细介绍 InnerInterceptor 的原理、用法和最佳实践,并提供代码示例。

一、为什么需要 InnerInterceptor?

  • 更轻量级: 相比于传统的 Interceptor,InnerInterceptor 更加轻量级,减少了不必要的拦截开销,提高了性能。
  • 更专注于 SQL 执行: InnerInterceptor 专注于 SQL 执行层面,可以让你更方便地修改 SQL 语句、参数或结果。
  • 简化配置: InnerInterceptor 的配置更加简单,无需手动注册,MyBatis Plus 会自动识别并注册。
  • 易于扩展:你可以通过实现 InnerInterceptor 接口,自定义 SQL 拦截逻辑。
  • 与 MyBatis Plus 无缝集成:InnerInterceptor 与 MyBatis Plus 的其他功能无缝集成,可以更好地发挥 MyBatis Plus 的优势。
  • 内置丰富功能: MyBatis Plus 提供了许多内置的 InnerInterceptor 实现,如分页插件、乐观锁插件、SQL性能分析插件等,可以直接使用。

二、InnerInterceptor 与 Interceptor 的区别

  • 拦截范围
    Interceptor 可以拦截 MyBatis 的 Executor、ParameterHandler、ResultSetHandler 和 StatementHandler 等组件,拦截范围更广。
    InnerInterceptor 主要拦截 SQL 执行过程中的 StatementHandler,拦截范围更窄,但更专注于 SQL 执行。
  • 执行时机
    Interceptor 可以拦截 SQL 执行过程中的多个阶段,例如参数处理、SQL 预编译、结果处理等。
    InnerInterceptor 主要拦截 StatementHandler 的 prepare 和 query 方法,更专注于 SQL 语句的准备和执行阶段。
  • 配置方式
    Interceptor 需要在 MyBatis 配置文件或 Spring Bean 中手动注册。
    InnerInterceptor 通过 MyBatis Plus 提供的 MybatisPlusInterceptor 统一注册管理,无需手动注册。
  • 代码复杂度
    Interceptor 的代码相对复杂,需要处理 Invocation 对象,并手动调用 proceed 方法。
    InnerInterceptor 的代码更加简洁,只需要重写对应的方法。
  • 性能
    Interceptor 由于拦截范围更广,可能会带来一定的性能开销。
    InnerInterceptor 由于拦截范围更窄,性能更高。

三、InnerInterceptor 的核心方法

  • void beforePrepare(StatementHandler sh, Connection connection,Integer transactionTimeout): 在 SQL 语句预编译之前调用。
  • void beforeQuery(StatementHandler sh, Connection connection, Integer transactionTimeout): 在 SQL 语句执行之前调用。
  • void afterQuery(StatementHandler sh, Connection connection, Integer transactionTimeout, Object result): 在 SQL 查询执行后调用。
  • void beforeUpdate(StatementHandler sh, Connection connection, Integer transactionTimeout): 在执行 INSERT 或 UPDATE 语句之前调用。
  • void afterUpdate(StatementHandler sh, Connection connection, Integer transactionTimeout,Object result): 在执行 INSERT 或 UPDATE 语句之后调用。

四、实践:使用 InnerInterceptor 修改 SQL 语句

4.1 创建 InnerInterceptor 实现类:

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import java.io.StringReader;
import java.sql.SQLException;

@Component
@Slf4j
public class MyInnerInterceptor implements InnerInterceptor {

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        String sql = boundSql.getSql();
        try {
            PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
            //sql处理
            String filterSql = addFilterCondition(sql);
            log.info("修改过后的sql:{}", filterSql);
            //修改sql
            mpBs.sql(filterSql);
        } catch (Exception e) {
            log.warn("动态修改sql:{}异常", sql, e);
            throw new SQLException("添加数据权限异常");
        }
    }

    public String addFilterCondition(String originalSql) throws JSQLParserException {
        CCJSqlParserManager parserManager = new CCJSqlParserManager();
        Select select = (Select) parserManager.parse(new StringReader(originalSql));
        PlainSelect plain = (PlainSelect) select.getSelectBody();
        Expression where_expression = plain.getWhere();
        // 这里可以根据需要增加过滤条件
        if (where_expression == null) {
            plain.setWhere(CCJSqlParserUtil.parseCondExpression("age = 35"));
        }
        return plain.toString();
    }
}

4.2 配置 MybatisPlusInterceptor

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.extend.chk.interceptor.MyInnerInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.List;

@Configuration
public class MyBatisPlusConfig {

    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;

    @Autowired
    private MyInnerInterceptor myInnerInterceptor;

    /**
     * 添加Mybatis拦截器
     * 主要是为了保证数据权限拦截器在分页插件拦截器之前执行sql的修改,如果不在这里手动添加的话,PageInterceptor会先执行
     * 先添加的拦截器后执行
     */
    @PostConstruct
    public void addMybatisInterceptor() {
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
            //将数据权限拦截器添加到MybatisPlusInterceptor拦截器链
            MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
            mybatisPlusInterceptor.addInnerInterceptor(myInnerInterceptor);
            //先添加PageHelper分页插件拦截器,再添加MybatisPlusInterceptor拦截器
            //configuration.addInterceptor(new PageInterceptor());
            configuration.addInterceptor(mybatisPlusInterceptor);
        }
    }
}

4.3 使用 InnerInterceptor

现在,你执行任何 SQL 语句,都会被 InnerInterceptor 拦截,你可以看到 SQL 语句已经被修改。

修改过后的sql:SELECT count(0) FROM t_user_info WHERE age = 35
修改过后的sql:SELECT id, name, password, age, status, last_login_time, token, create_by, create_time, update_by, update_time, remark FROM t_user_info WHERE age = 35 LIMIT ?

五、内置拦截器

除了自定义拦截器外,MyBatis-Plus 还提供了多个内置拦截器,可以直接使用或作为参考来创建自己的拦截器。以下是几个常用的内置拦截器:

  • PaginationInterceptor:分页插件,支持多种数据库的分页查询。
  • PerformanceAnalyzerInterceptor:性能分析插件,记录每条 SQL 的执行时间和影响行数。
  • OptimisticLockerInterceptor:乐观锁插件,用于防止并发更新时的数据覆盖问题。
  • BlockAttackInterceptor:阻止恶意攻击插件,防止批量删除或更新操作导致数据丢失。

六、常见应用场景

  • SQL 日志记录:如上文所示,记录每次 SQL 执行的时间、参数及结果,便于调试和性能分析。
  • 分页插件:动态地为查询语句添加分页条件,而无需修改原有的 Mapper 文件。
  • SQL 性能监控:统计每条 SQL 的执行次数、平均耗时等指标,帮助识别潜在的性能瓶颈。
  • 缓存实现:基于拦截器实现简单的查询结果缓存,减少不必要的数据库访问。
  • 数据脱敏:在查询结果返回之前,对敏感字段进行加密或替换,确保数据安全。
  • 权限控制:在 SQL 执行前检查用户权限,防止未经授权的操作。

七、最佳实践

  • 按需选择拦截器: 根据实际需求选择合适的拦截器,如果需要修改 SQL 语句、参数或结果,可以使用 InnerInterceptor,如果需要拦截 MyBatis 的其他组件,可以使用 Interceptor。
  • 细粒度控制: 可以根据 MappedStatement 的 ID 或 SQL 语句内容,细粒度控制 InnerInterceptor 的执行范围。
  • 使用内置的 InnerInterceptor: MyBatis Plus 提供了许多内置的 InnerInterceptor 实现,如分页插件、乐观锁插件、SQL 性能分析插件等,可以直接使用,无需重复开发。
  • 避免耗时操作: InnerInterceptor 会在 SQL 执行的关键节点执行,避免在其中执行耗时的操作,以免影响性能。
  • 异常处理: 在 InnerInterceptor 方法中使用 try-catch 代码块处理可能抛出的异常,避免影响正常业务逻辑。
  • 配置顺序: 如果存在多个 InnerInterceptor,Mybatis Plus 会根据 addInnerInterceptor 方法的调用顺序进行执行。
  • 使用 MyBatis Plus 工具类: MyBatis Plus 提供了一些工具类,例如 PluginUtils,可以方便地访问和修改 SQL 语句、参数等信息。

到此这篇关于MyBatis Plus中InnerInterceptor的实现的文章就介绍到这了,更多相关MyBatisPlus InnerInterceptor内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • 在已经使用mybatis的项目里引入mybatis-plus,结果不能共存的解决

    在已经使用mybatis的项目里引入mybatis-plus,结果不能共存的解决

    这篇文章主要介绍了在已经使用mybatis的项目里引入mybatis-plus,结果不能共存的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Java并发编程之线程创建介绍

    Java并发编程之线程创建介绍

    这篇文章主要介绍了Java并发编程之线程创建,进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是一个实体,一个进程中至少有一个线程,下文更多相关内容需要的小伙伴可以参考一下
    2022-04-04
  • 多数据源如何实现事务管理

    多数据源如何实现事务管理

    Spring中涉及三个核心事务处理接口:PlatformTransactionManager、TransactionDefinition和TransactionStatus,PlatformTransactionManager提供事务操作的基本方法,如获取事务、提交和回滚
    2024-09-09
  • Java 实战项目之在线点餐系统的实现流程

    Java 实战项目之在线点餐系统的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+SSM+jsp+mysql+maven实现一个在线点餐系统,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • 在IDEA中配置tomcat并创建tomcat项目的图文教程

    在IDEA中配置tomcat并创建tomcat项目的图文教程

    这篇文章主要介绍了在IDEA中配置tomcat并创建tomcat项目的图文教程,需要的朋友可以参考下
    2020-07-07
  • java按照模板导出pdf或word文件详细代码

    java按照模板导出pdf或word文件详细代码

    有时候业务中我们需要使用pdf模板生成一份pdf文件,下面这篇文章主要给大家介绍了关于java按照模板导出pdf或word文件的相关资料,文中给出了详细的代码示例,需要的朋友可以参考下
    2023-11-11
  • Java中异常Exception和捕获以及自定义异常详解

    Java中异常Exception和捕获以及自定义异常详解

    在工作过程中,我们常常需要在合适的地方抛出合适的异常,除了java自带的一些异常,我们可以在项目中定制自己的异常,并且全局捕获它,下面这篇文章主要给大家介绍了关于Java中异常Exception和捕获以及自定义异常的相关资料,需要的朋友可以参考下
    2023-05-05
  • springboot如何根据不同的日志级别显示不同的颜色

    springboot如何根据不同的日志级别显示不同的颜色

    这篇文章主要介绍了springboot如何根据不同的日志级别显示不同的颜色问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • SprinBoot如何集成参数校验Validator及参数校验的高阶技巧

    SprinBoot如何集成参数校验Validator及参数校验的高阶技巧

    这篇文章主要介绍了SprinBoot如何集成参数校验Validator及参数校验的高阶技巧包括自定义校验、分组校验,本文分步骤给大家介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • Java substring原理及使用方法实例

    Java substring原理及使用方法实例

    这篇文章主要介绍了Java substring原理及使用方法实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06

最新评论