深入 MyBatis-Plus 插件:解锁高级数据库功能

一、关于Mybatis-Plus插件

1.1 简介

Mybatis-Plus 提供了丰富的插件机制,这些插件可以帮助开发者更方便地扩展 Mybatis 的功能,提升开发效率、优化性能和实现一些常用的功能。

1.2 实现原理

Mybatis-Plus 的插件实现是基于 MyBatis 的拦截器机制, 这些插件通过 MybatisPlusInterceptor​ 来实现对 MyBatis 执行过程的拦截和增强。

MyBatis 插件本质上是对 SQL 执行过程的拦截和扩展,Mybatis-Plus 插件通过在 MyBatis 的执行生命周期中插入拦截器来实现一些增强功能。通过这种方式,Mybatis-Plus 可以实现分页、性能分析、乐观锁等功能的自动化处理。

MybatisPlusInterceptor 概览

MybatisPlusInterceptor​ 是 MyBatis-Plus 的核心插件,它代理了 MyBatis 的 Executor#query​、Executor#update​ 和 StatementHandler#prepare​ 方法,允许在这些方法执行前后插入自定义逻辑。

属性

MybatisPlusInterceptor​ 有一个关键属性 interceptors​,它是一个 List<InnerInterceptor>​ 类型的集合,用于存储所有要应用的内部拦截器。

InnerInterceptor 接口

所有 MyBatis-Plus 提供的插件都实现了 InnerInterceptor​ 接口,这个接口定义了插件的基本行为。目前,MyBatis-Plus 提供了以下插件:

  • 自动分页 : PaginationInnerInterceptor
  • 多租户 : TenantLineInnerInterceptor
  • 动态表名 : DynamicTableNameInnerInterceptor
  • 乐观锁 : OptimisticLockerInnerInterceptor
  • SQL 性能规范 : IllegalSQLInnerInterceptor
  • 防止全表更新与删除 : BlockAttackInnerInterceptor

1.3 配置方式

插件的配置可以在 Spring 配置中进行,也可以在 Spring Boot 项目中通过 Java 配置来添加。以下是两种配置方式的示例:

  • Spring 配置 :在 Spring 配置中,需要创建 MybatisPlusInterceptor 的实例,并将它添加到 MyBatis 的插件列表中。
  • Spring Boot 配置:在 Spring Boot 项目中,可以通过 Java 配置来添加插件,例如添加分页插件。

Spring Boot 配置示例

java 复制代码
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

配置多个插件

java 复制代码
@Configuration
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        // 添加性能分析插件
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(1000); // 设置SQL最大执行时间,单位为毫秒
        interceptor.addInnerInterceptor(performanceInterceptor);

        // 添加防全表更新与删除插件
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());

        return interceptor;
    }
}

注意

使用多个插件时,需要注意它们的顺序。建议的顺序是:

  1. 多租户、动态表名
  2. 分页、乐观锁
  3. SQL 性能规范、防止全表更新与删除

总结:对 SQL 进行单次改造的插件应优先放入,不对 SQL 进行改造的插件最后放入。

二、分页插件(PaginationInnerInterceptor​)

2.1 关于

简介

MyBatis-Plus 的分页插件 PaginationInnerInterceptor​ 提供了强大的分页功能,支持多种数据库,使得分页查询变得简单高效。用时只需要在查询方法中传入Page<T>​对象,插件会自动处理分页相关的SQL构建和结果集解析。

主要功能

  1. 自动分页

    • 通过在查询时自动添加 LIMITOFFSET 等 SQL 关键字,来实现分页功能。
  2. 兼容性

    • 支持多种数据库的分页语法,确保在不同数据库上都能正常工作。
  3. 动态参数

    • 可以动态地根据用户的请求参数(如页码和每页大小)生成分页信息,而无需手动处理 SQL。
  4. 性能优化

    • 在执行分页查询时,通过设置合理的参数,能够减少查询的时间复杂度,提高查询效率。

关键参数

  • DbType :指定数据库类型,影响生成的分页 SQL 语句。例如,DbType.MYSQL 会生成适用于 MySQL 的分页语句。
  • setOverflow:允许配置是否允许请求的页码超出最大页码范围(例如,返回最后一页的数据)。
  • setMaxLimit:可以设置每页最大记录数,避免用户请求过大的分页数据。

2.2 使用

配置插件

java 复制代码
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
}

分页查询

java 复制代码
Page<User> page = new Page<>(1, 10);  // 当前页, 每页记录数
IPage<User> userPage = userMapper.selectPage(page, null);  

三、性能分析插件(PerformanceInterceptor​)

3.1 关于

简介

性能分析插件(PerformanceInterceptor​)是 MyBatis-Plus 提供的一个非常有用的工具,它可以用来监控 SQL 语句的执行时间,帮助开发者及时发现和优化慢查询问题。

3.2 使用

配置插件

java 复制代码
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PerformanceInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加性能分析插件
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(1000); // 设置SQL最大执行时间,单位为毫秒
        interceptor.addInnerInterceptor(performanceInterceptor);
        return interceptor;
    }
}

配置日志输出

为了更好地监控 SQL 语句的执行情况,可以配置日志输出。在 application.properties​ 或 application.yml​ 文件中添加日志配置:

yml 复制代码
logging:
  level:
    com.baomidou.mybatisplus: DEBUG

  • SQL 执行时间记录:每次执行 SQL 语句时,插件会记录执行时间。
  • 超时处理 :如果 SQL 语句的执行时间超过 setMaxTime 方法设置的阈值(默认为 0,表示不限制),插件会记录一条警告日志或抛出异常,具体行为取决于配置。

如果 SQL 语句执行时间超过设定的阈值,日志输出可能如下所示:

bash 复制代码
2024-11-08 10:41:00 [http-nio-8080-exec-1] WARN  c.b.mybatisplus.extension.plugins.inner.PerformanceInterceptor - [performance] SQL Execution Time: 1500 ms

通过以上步骤,你可以在 MyBatis-Plus 中轻松配置和使用性能分析插件,帮助你及时发现和优化慢查询问题。

四、防全表更新与删除插件(BlockAttackInterceptor​)

4.1 关于

简介

MyBatis-Plus 提供了一个防全表更新与删除插件(BlockAttackInterceptor​),该插件可以防止在没有 WHERE 条件的情况下执行全表更新或删除操作,从而避免误操作导致的数据丢失或损坏

使用

配置插件
java 复制代码
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加防全表更新与删除插件
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        return interceptor;
    }
}

测试

在控制器层中调用 Service 层的方法进行查询。

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/delete-all")
    public String deleteAllUsers() {
        try {
            userService.remove(null); // 尝试删除所有用户
            return "All users deleted successfully";
        } catch (Exception e) {
            return "Failed to delete all users: " + e.getMessage();
        }
    }

    @PostMapping("/update-all")
    public String updateAllUsers() {
        try {
            User user = new User();
            user.setName("Updated Name");
            userService.updateById(user); // 尝试更新所有用户
            return "All users updated successfully";
        } catch (Exception e) {
            return "Failed to update all users: " + e.getMessage();
        }
    }
}
  1. 尝试删除所有用户 :访问 /users/delete-all​ 接口。

    • 如果没有 WHERE 条件,插件会抛出异常并阻止删除操作。

    • 控制台输出示例:

      bash 复制代码
      Failed to delete all users: Cannot execute delete operation without where condition!
  2. 尝试更新所有用户 :访问 /users/update-all​ 接口。

    • 如果没有 WHERE 条件,插件会抛出异常并阻止更新操作。

    • 控制台输出示例:

      bash 复制代码
      Failed to update all users: Cannot execute update operation without where condition!

五、自定义插件

如果内置插件不能满足需求,可以自定义插件。自定义插件需要实现 Interceptor​ 或 InnerInterceptor​ 接口,并在 intercept​ 方法中实现自定义逻辑。

示例:

java 复制代码
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
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;

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

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 自定义逻辑
        System.out.println("CustomInterceptor: Before SQL execution");
        Object result = invocation.proceed();
        System.out.println("CustomInterceptor: After SQL execution");
        return result;
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}

注册自定义插件:

java 复制代码
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new CustomInterceptor());
    return interceptor;
}

通过上述机制和接口,MyBatis-Plus 提供了灵活的插件扩展能力,使开发者可以根据具体需求定制化功能。

相关推荐
高山上有一只小老虎1 小时前
mybatisplus分页查询版本 3.5.8 以下和版本 3.5.9及以上的区别
java·spring boot·mybatis
人道领域1 小时前
javaWeb从入门到进阶(MyBatis拓展)
java·tomcat·mybatis
J2虾虾10 小时前
SpringBoot和mybatis Plus不兼容报错的问题
java·spring boot·mybatis
pp起床1 天前
【苍穹外卖】Day03 菜品管理
java·数据库·mybatis
九皇叔叔1 天前
【01】SpringBoot3 MybatisPlus 工程创建
java·mybatis·springboot3·mybatis plus
BD_Marathon1 天前
MyBatis逆向工程之清晰简洁版
mybatis
九皇叔叔1 天前
【02】SpringBoot3 MybatisPlus 加入日志功能
java·mysql·mybatis·日志·mybatisplus
齐 飞1 天前
MybatisPlus真正的批量新增
spring boot·mybatis
小北方城市网1 天前
Spring Cloud Gateway 生产问题排查与性能调优全攻略
redis·分布式·缓存·性能优化·mybatis
while(1){yan}1 天前
Spring事务
java·数据库·spring boot·后端·java-ee·mybatis