Mybatis-Plus 提供了丰富的插件机制,这些插件可以帮助开发者更方便地扩展 Mybatis 的功能,提升开发效率、优化性能和实现一些常用的功能。
Mybatis-Plus 的插件实现是基于 MyBatis 的拦截器机制, 这些插件通过 MybatisPlusInterceptor
来实现对 MyBatis 执行过程的拦截和增强。
MyBatis 插件本质上是对 SQL 执行过程的拦截和扩展,Mybatis-Plus 插件通过在 MyBatis 的执行生命周期中插入拦截器来实现一些增强功能。通过这种方式,Mybatis-Plus 可以实现分页、性能分析、乐观锁等功能的自动化处理。
MybatisPlusInterceptor
是 MyBatis-Plus 的核心插件,它代理了 MyBatis 的 Executor#query
、Executor#update
和 StatementHandler#prepare
方法,允许在这些方法执行前后插入自定义逻辑。
MybatisPlusInterceptor
有一个关键属性 interceptors
,它是一个 List<InnerInterceptor>
类型的集合,用于存储所有要应用的内部拦截器。
所有 MyBatis-Plus 提供的插件都实现了 InnerInterceptor
接口,这个接口定义了插件的基本行为。目前,MyBatis-Plus 提供了以下插件:
PaginationInnerInterceptor
TenantLineInnerInterceptor
DynamicTableNameInnerInterceptor
OptimisticLockerInnerInterceptor
IllegalSQLInnerInterceptor
BlockAttackInnerInterceptor
插件的配置可以在 Spring 配置中进行,也可以在 Spring Boot 项目中通过 Java 配置来添加。以下是两种配置方式的示例:
MybatisPlusInterceptor
的实例,并将它添加到 MyBatis 的插件列表中。Spring Boot 配置示例
@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;
}
}
配置多个插件
@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;
}
}
注意 使用多个插件时,需要注意它们的顺序。建议的顺序是:
总结:对 SQL 进行单次改造的插件应优先放入,不对 SQL 进行改造的插件最后放入。
PaginationInnerInterceptor
)MyBatis-Plus 的分页插件 PaginationInnerInterceptor
提供了强大的分页功能,支持多种数据库,使得分页查询变得简单高效。用时只需要在查询方法中传入Page<T>
对象,插件会自动处理分页相关的SQL构建和结果集解析。
LIMIT
和 OFFSET
等 SQL 关键字,来实现分页功能。
DbType.MYSQL
会生成适用于 MySQL 的分页语句。
@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;
}
}
Page<User> page = new Page<>(1, 10); // 当前页, 每页记录数
IPage<User> userPage = userMapper.selectPage(page, null);
PerformanceInterceptor
)性能分析插件(PerformanceInterceptor
)是 MyBatis-Plus 提供的一个非常有用的工具,它可以用来监控 SQL 语句的执行时间,帮助开发者及时发现和优化慢查询问题。
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
文件中添加日志配置:
logging:
level:
com.baomidou.mybatisplus: DEBUG
setMaxTime
方法设置的阈值(默认为 0,表示不限制),插件会记录一条警告日志或抛出异常,具体行为取决于配置。
如果 SQL 语句执行时间超过设定的阈值,日志输出可能如下所示:
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
)MyBatis-Plus 提供了一个防全表更新与删除插件(BlockAttackInterceptor
),该插件可以防止在没有 WHERE 条件的情况下执行全表更新或删除操作,从而避免误操作导致的数据丢失或损坏
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 层的方法进行查询。
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();
}
}
}
/users/delete-all
接口。
/users/update-all
接口。
如果内置插件不能满足需求,可以自定义插件。自定义插件需要实现 Interceptor
或 InnerInterceptor
接口,并在 intercept
方法中实现自定义逻辑。
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);
}
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new CustomInterceptor());
return interceptor;
}
通过上述机制和接口,MyBatis-Plus 提供了灵活的插件扩展能力,使开发者可以根据具体需求定制化功能。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。