MyBatis-Plus 拦截器

MyBatis-Plus 拦截器

MyBatis-Plus 是一个基于 MyBatis 的增强工具,旨在简化数据库操作的复杂性,提高开发效率。在 MyBatis-Plus 中,拦截器是一种强大的功能,允许你在 SQL 执行前后进行自定义的操作。本文将详细探讨 MyBatis-Plus 拦截器的工作原理、使用方法以及应用场景。

一、什么是 MyBatis-Plus 拦截器?

MyBatis-Plus 拦截器是一个实现了 MyBatis 拦截器接口的组件,可以在 MyBatis 的执行过程中拦截和处理 SQL 语句。它允许开发者在 SQL 执行前后插入自定义的逻辑,例如记录日志、修改 SQL 语句等。

二、MyBatis-Plus 拦截器的工作原理

MyBatis-Plus 拦截器的核心是 MyBatis 提供的 Interceptor 接口。开发者可以通过实现 Interceptor 接口来创建自定义的拦截器。MyBatis 在执行 SQL 语句时,会调用这些拦截器的相应方法,从而实现自定义的操作。

拦截器的工作流程如下:

  1. 注册拦截器:在 MyBatis 配置文件中或通过 Spring Boot 的配置文件中注册自定义拦截器。
  2. 拦截 SQL 执行:拦截器会在 SQL 执行的过程中被调用,你可以在这些拦截器中实现自定义逻辑。
  3. 执行后处理:拦截器可以在 SQL 执行后对结果进行处理,或者在 SQL 执行前对 SQL 进行修改。
1. MyBatis 拦截器机制概述

MyBatis 的拦截器机制允许开发者在 MyBatis 的执行流程中插入自定义逻辑。MyBatis 的拦截器可以拦截四个主要的组件:

  • Executor:负责执行 SQL 语句的组件。
  • StatementHandler:负责准备 SQL 语句并将其传递给数据库的组件。
  • ParameterHandler:负责将参数设置到 SQL 语句中的组件。
  • ResultSetHandler:负责处理查询结果集的组件。

拦截器通过实现 Interceptor 接口,并在 @Signature 注解中指定要拦截的方法,可以拦截这些组件的操作方法。

2. MyBatis 拦截器的生命周期
  1. 拦截器注册 :在 MyBatis 配置文件中或通过 SqlSessionFactory 配置时注册拦截器。
  2. 拦截器实例化 :MyBatis 会创建拦截器实例,并通过 plugin 方法对目标对象进行包装。
  3. 方法拦截 :在目标方法执行前后,拦截器可以插入自定义逻辑。在执行 intercept 方法时,可以通过 Invocation 对象访问目标方法的信息。
  4. 目标方法执行 :拦截器在执行自定义逻辑后,通常会调用目标方法的 proceed 方法,确保原始功能得以保留。
  5. 拦截器链:多个拦截器可以链式调用,依次拦截目标方法。

三、如何使用 MyBatis-Plus 拦截器

1. 创建自定义拦截器

首先,你需要实现 Interceptor 接口。以下是一个简单的自定义拦截器的示例:

java 复制代码
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.Signature;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties;

@Intercepts({
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyCustomInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取 StatementHandler 对象
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        
        // 打印 SQL 语句
        System.out.println("Intercepted SQL: " + statementHandler.getBoundSql().getSql());
        
        // 执行原始的处理过程
        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {
        // 可以通过 properties 设置一些属性
    }
}

2. 注册拦截器

自定义拦截器的注册可以通过 MyBatis 配置文件或 Spring Boot 配置类进行

java 复制代码
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.google.common.collect.Lists;
import com.aa.bb.cc.dd.test.handler.QueryStatisticsInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.ClassPathMapperScanner;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;

@Slf4j
@Configuration
public class OPPConfiguration implements EnvironmentAware,BeanFactoryAware{

	@Autowired(required = false)
	private DataSource dataSource;

	private BeanFactory beanFactory;

	@Bean("sqlSessionFactory")
	@Primary
	public SqlSessionFactory sqlSessionFactory() throws Exception {

		MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(this.dataSource);
		sqlSessionFactoryBean.setMapperLocations(new   PathMatchingResourcePatternResolver().getResources("classpath*:com/aa/bb/cc/**/mapper/**/**.xml"));
		sqlSessionFactoryBean.setVfs(SpringBootVFS.class);
		MybatisPlusInterceptor interceptor=new MybatisPlusInterceptor();

		List<InnerInterceptor> interceptors = Lists.newArrayList(interceptor.getInterceptors());
		interceptors.clear();
		PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
		// 分页插件
		interceptors.add(paginationInnerInterceptor);
		// 乐观锁插件
		interceptors.add(new OptimisticLockerInnerInterceptor());

		interceptor.setInterceptors(interceptors);
		GlobalConfig globalConfig = GlobalConfigUtils.defaults();
		GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
		globalConfig.setDbConfig(dbConfig);
		globalConfig.setMetaObjectHandler(new OpaMetaObjectHandler());

		globalConfig.setSqlInjector(new EasySqlInjector());
		sqlSessionFactoryBean.setGlobalConfig(globalConfig);
		sqlSessionFactoryBean.getObject().getConfiguration().addInterceptor(interceptor);
        //注册自定义拦截器
		sqlSessionFactoryBean.getObject().getConfiguration().addInterceptor(new QueryStatisticsInterceptor());

		SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBean.getObject();
		SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
		ClassPathMapperScanner scanner = new ClassPathMapperScanner((BeanDefinitionRegistry) beanFactory);
		scanner.setSqlSessionTemplate(sqlSessionTemplate);
		scanner.registerFilters();
		scanner.scan("com.aa.bb.cc.cc.test.dao","com.aa.bb.cc.dao");
		return sqlSessionFactoryBean.getObject();
	}

3. 使用拦截器

创建了自定义拦截器并注册后,当 SQL 执行时,MyCustomInterceptor 将拦截并打印 SQL 语句。你可以根据需要在 intercept 方法中实现更复杂的逻辑,如修改 SQL、记录日志等。

四、常见拦截器应用场景

  1. SQL 日志记录:记录所有执行的 SQL 语句及其执行时间,以便进行性能监控和调试。
  2. 动态 SQL 修改:在执行前动态修改 SQL 语句,如添加调试信息或修改查询条件。
  3. 性能监控:记录 SQL 执行时间,分析性能瓶颈。
  4. 权限控制:根据用户权限动态修改 SQL 查询。

五、常见 MyBatis Plus 拦截器

  • 分页拦截器

分页拦截器 PaginationInterceptor 是 MyBatis Plus 提供的一个重要拦截器,用于处理分页查询。它会自动识别分页参数,并在 SQL 中添加相应的分页条件。

  • 乐观锁拦截器

乐观锁拦截器 OptimisticLockerInterceptor 用于处理乐观锁机制,确保在并发更新时数据的一致性。它会在 SQL 中添加 version 字段,以支持乐观锁的检查和更新。

  • 性能分析拦截器

性能分析拦截器 PerformanceInterceptor 用于打印 SQL 执行的性能分析信息,包括 SQL 执行时间等。它帮助开发者识别性能瓶颈和优化 SQL 查询。

六、注意事项

  1. 性能影响:拦截器的逻辑会增加额外的开销,尤其是在复杂的拦截器中,因此要注意性能影响。
  2. 调试与测试:在使用拦截器时,要确保对其进行充分的测试,以避免引入潜在的 bug。
  3. 兼容性:不同版本的 MyBatis 和 MyBatis-Plus 可能对拦截器的支持有所不同,确保使用兼容的版本。

结语

MyBatis-Plus 拦截器为开发者提供了强大的自定义能力,可以在 SQL 执行过程中插入各种业务逻辑。通过合理使用拦截器,可以大大提升开发效率和系统性能。希望本文对你了解和使用 MyBatis-Plus 拦截器有所帮助。

相关推荐
M00SE22 分钟前
解决mybatis plus 中 FastjsonTypeHandler无法正确反序列化List类型的问题
mybatis
来一杯龙舌兰1 小时前
【JAVA】自动生成常量类、自动生成所需代码(附源码)
java·开发语言·c#·自动生成代码
Flying_Fish_roe1 小时前
Spring Boot-依赖冲突问题
java·linux·spring boot
月临水1 小时前
JavaEE:网络编程(套接字)
java·网络·java-ee
国通快递驿站1 小时前
AntFlow系列教程二之流程同意
java·开发语言
宏基骑士1 小时前
【java面向对象二】static(一)
java·开发语言
IT学长编程1 小时前
计算机毕业设计 基于SpringBoot框架的网上蛋糕销售系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·毕业论文·计算机毕业设计选题·计算机毕业设计开题报告·网上蛋糕销售系统
尘浮生2 小时前
Java项目实战II基于Java+Spring Boot+MySQL的服装厂服装生产管理系统的设计与实现
java·开发语言·spring boot·后端·mysql·maven·intellij-idea
箬敏伊儿2 小时前
打包好的jar包,如何部署在服务器?——详细教程
java·服务器·python·jar
这孩子叫逆2 小时前
25. MyBatis中的RowBounds是什么?如何实现内存分页?
数据库·mybatis