MyBatis-Plus 基于 MyBatis 的插件机制,提供了一系列实用插件,可快速实现分页、防全表操作、乐观锁等功能。这些插件通过拦截 SQL 执行流程,在不侵入业务代码的前提下增强框架能力。
一、MyBatis-Plus 插件机制基础
1. 插件原理
MyBatis 的插件机制基于 JDK 动态代理,通过拦截 Executor
、StatementHandler
、ParameterHandler
、ResultSetHandler
四个核心接口的方法,在 SQL 执行的关键节点插入自定义逻辑。
MyBatis-Plus 的插件均实现 InnerInterceptor
接口,通过 MybatisPlusInterceptor
拦截器链统一管理,只需简单配置即可生效。
2. 插件注册方式
所有插件需通过 MybatisPlusInterceptor
注册,示例如下:
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 注册插件(可添加多个)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 分页插件
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); // 防全表操作插件
return interceptor;
}
}
二、核心插件案例
1. 分页插件(PaginationInnerInterceptor)
分页是数据库操作的高频需求,MyBatis-Plus 分页插件可自动拼接分页 SQL,无需手动编写 LIMIT
语句。
配置步骤:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 指定数据库类型(MySQL)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
分页查询示例:
@Test
public void testPage() {
// 创建分页条件:第1页(从0开始),每页2条数据
Page<Student> page = new Page<>(0, 2);
// 执行分页查询(第二个参数为查询条件,可传null)
IPage<Student> resultPage = studentMapper.selectPage(page, null);
// 分页结果解析
System.out.println("总条数:" + resultPage.getTotal());
System.out.println("总页数:" + resultPage.getPages());
System.out.println("当前页数据:" + resultPage.getRecords());
}
原理:
插件会拦截 Executor
的 query
方法,根据数据库类型自动在 SQL 后拼接分页语句(如 MySQL 的 LIMIT
),同时查询总条数,封装成 IPage
对象返回。
2. 防止全表更新与删除插件(BlockAttackInnerInterceptor)
该插件用于拦截全表更新或删除操作,避免因误操作导致的数据丢失,适合开发环境使用。
配置步骤:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 添加防全表操作插件
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
拦截效果:
当执行无条件的全表更新/删除时,插件会抛出异常:
// 全表删除(会被拦截)
@Test
public void testDeleteAll() {
// 无查询条件的删除会触发拦截
studentMapper.delete(new QueryWrapper<>());
}
执行后会抛出 BlockAttackException
,提示“不允许全表删除”。
注意:
- 仅支持 MySQL 5.6.3 以上版本;
- 生产环境建议谨慎使用,避免影响正常业务操作。
3. 乐观锁插件(OptimisticLockerInnerInterceptor)
乐观锁用于解决并发场景下的数据冲突,通过版本号机制实现:更新时检查版本号,若一致则更新并递增版本号,否则更新失败。
实现步骤:
(1)配置插件:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 其他插件...
// 添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
(2)实体类添加版本字段:
@Data
public class Student {
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private Integer age;
// 版本字段,添加@Version注解
@Version
private Integer version;
}
(3)数据库添加版本列:
ALTER TABLE student ADD COLUMN version INT DEFAULT 0;
(4)测试乐观锁:
@Test
public void testOptimisticLock() {
// 1. 查询数据(获取当前版本号)
Student student = studentMapper.selectById(1); // version=0
// 2. 模拟并发更新
Student student2 = studentMapper.selectById(1); // 另一个线程也获取version=0
// 线程1更新(成功,version变为1)
student.setName("线程1更新");
studentMapper.updateById(student);
// 线程2更新(失败,版本号已变化)
student2.setName("线程2更新");
int rows = studentMapper.updateById(student2);
System.out.println("线程2更新影响行数:" + rows); // 输出0,更新失败
}
三、插件执行顺序与冲突处理
执行顺序:
插件在MybatisPlusInterceptor
中的添加顺序即执行顺序,建议按“分页插件 → 防全表操作插件 → 乐观锁插件”的顺序配置。冲突处理:
- 乐观锁插件与防全表操作插件可同时使用,无冲突;
- 若自定义插件与内置插件功能重叠,需注意拦截逻辑的优先级。
四、自定义插件扩展
除内置插件外,可通过实现 InnerInterceptor
接口开发自定义插件。例如,实现一个 SQL 日志打印插件:
public class SqlLogInterceptor implements InnerInterceptor {
@Override
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
// 获取SQL语句
BoundSql boundSql = sh.getBoundSql();
String sql = boundSql.getSql();
System.out.println("执行SQL:" + sql);
}
}
// 注册自定义插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new SqlLogInterceptor()); // 自定义插件
return interceptor;
}
总结
MyBatis-Plus 插件体系通过拦截 SQL 执行流程,提供了分页、防全表操作、乐观锁等实用功能,大幅简化了开发工作。核心插件的使用需注意:
- 分页插件需指定数据库类型,确保分页语句正确;
- 防全表操作插件适合开发环境,防止误操作;
- 乐观锁通过版本号机制解决并发冲突,需正确配置版本字段。