MP 分页插件与乐观锁插件
MP 的插件通过 MybatisPlusInterceptor 统一注册(3.4 起的推荐机制,旧 PaginationInterceptor 已废弃,以官方文档为准)。本节配置最常用的两个:分页插件与乐观锁插件。
插件注册骨架
一个拦截器链,多个内部插件按注册顺序工作:
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
多插件叠加时顺序影响行为(如多租户、动态表名等要放外层),组合用法以官方文档为准。
分页插件
PaginationInnerInterceptor 拦截分页查询:自动补 COUNT 查总数、按方言生成 LIMIT。DbType 要与数据库匹配(MYSQL / POSTGRE_SQL / ORACLE 等)。用法:
Page<User> page = new Page<>(2, 10); // 第 2 页,每页 10 条
// 方式一:Mapper 传 Page
Page<User> result = userMapper.selectPage(page,
Wrappers.<User>lambdaQuery().eq(User::getStatus, 1));
// 方式二:Service 层
Page<User> result2 = userService.page(page,
Wrappers.<User>lambdaQuery().orderByDesc(User::getCreateTime));
System.out.println(result.getTotal()); // 输出:总数(自动 COUNT)
System.out.println(result.getRecords().size()); // 输出:本页条数,如 10
注意点:
- 分页插件对主查询改写 SQL(COUNT + LIMIT),入参放 Page 即生效,返回 List 也可(以官方文档为准);
- 一对多 join 分页的坑依然存在(见前面章节),复杂场景先分页主表再拼子表;
- 深分页(LIMIT 100000,10)性能差,数据量大改用游标/按上次最大 id 的条件分页。
乐观锁插件
乐观锁前提:表有版本列 + 实体标注 @Version:
public class User {
@TableId(type = IdType.AUTO)
private Long id;
// ...
@Version // 版本号
private Integer version;
}
更新时插件自动改写 SQL:
-- 开发者写:UPDATE user SET name=? WHERE id=?
-- 插件改写:UPDATE user SET name=?, version=version+1
-- WHERE id=? AND version=旧version
影响行数为 0 说明 version 已被别人改过,业务侧重试:
User u = userService.getById(1L);
u.setName("新名字");
int rows = userMapper.updateById(u); // 带乐观锁条件
if (rows == 0) {
// 冲突:提示用户或重新读取后再试
}
使用注意:version 由插件维护,不要手动 +1;乐观锁适合冲突少的更新,高冲突场景用悲观锁/分布式锁更合适;updateById(entity) 与 update(entity, wrapper) 的支持细节以官方文档为准。
两个插件都是"注册一次、全局生效":PaginationInnerInterceptor 消灭分页样板 SQL,OptimisticLockerInnerInterceptor 用版本号杜绝更新覆盖。先配好拦截器链,再按"Page 入参、@Version 标注"两步使用即可。