分页插件、XML自定义分页、乐观锁
1)分页插件(最常用)
1.1 插件作用与核心点
- MyBatis-Plus 自带分页能力:配置好拦截器后,写分页就像写普通查询一样。
- 关键类:
MybatisPlusInterceptor+PaginationInnerInterceptor(DbType.MYSQL)。
1.2 代码:分页插件配置(Spring Boot)
@Configuration
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
1.3 代码:分页查询测试(selectPage)
@Test
public void testPage(){
Page<User> page = new Page<>(1, 5); // 当前页=1,每页=5
userMapper.selectPage(page, null);
List<User> list = page.getRecords();
System.out.println("当前页:"+page.getCurrent());
System.out.println("每页显示的条数:"+page.getSize());
System.out.println("总记录数:"+page.getTotal());
System.out.println("总页数:"+page.getPages());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有下一页:"+page.hasNext());
}
1.4 常见坑
- DbType 要写对:MySQL 就用
DbType.MYSQL,否则分页 SQL 可能不正确。 selectPage(page, wrapper)的第二个参数可用条件构造器;写null表示无条件。
2)XML 自定义分页(分页 + 自己写SQL)
2.1 为什么需要它?
当你想写更复杂的 SQL(多表、复杂字段、特定排序)时,用 XML 自定义查询,但仍想要 MP 的分页能力,就用它。讲义的示例就是“按年龄查询用户列表,分页显示”。
2.2 Mapper 接口:Page 参数必须放第一位
/**
* 根据年龄查询用户列表,分页显示
* Page 参数必须放在第一位
*/
IPage<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
这条“Page 必须放第一位”的规则非常关键。
2.3 XML:写自己的 SQL
<sql id="BaseColumns">id,username,age,email</sql>
<select id="selectPageVo" resultType="User">
SELECT <include refid="BaseColumns"/>
FROM t_user
WHERE age > #{age}
</select>
抽字段片段 + 自定义 select。
2.4 测试调用
@Test
public void testSelectPageVo(){
Page<User> page = new Page<>(1, 5);
userMapper.selectPageVo(page, 20);
System.out.println(page.getRecords());
}
3)乐观锁(解决“更新覆盖”问题)
3.1 场景理解(先搞懂为什么要锁)
讲义用“商品调价”故事说明:两个用户同时读到旧价格,各自更新,后提交的人会覆盖前者,造成严重错误。
3.2 乐观锁核心机制(记住这 3 句话)
- 表里加
version字段 - 取出数据时带上 version
- 更新时
version = version + 1,并且where里带version,不匹配就更新失败
3.3 实操步骤
(1) 建表:加 version 列
讲义示例表:t_product 带 VERSION。
(2) 实体类:version 上加 @Version
@Data
public class Product {
private Long id;
private String name;
private Integer price;
@Version
private Integer version;
}
讲义明确用 @Version 标记版本号字段。
(3) 配置插件:OptimisticLockerInnerInterceptor
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
(4) 冲突现象:第二次更新返回 0(更新失败)
:第二个人更新时 version 条件不成立,修改失败。
3.4 失败重试(工程里常见)
思路:如果更新结果 result2 == 0,就重新查一次(拿到新 version)再更新。
你可以按这个顺序练(10~30分钟一轮)
- 先把分页插件跑通:
selectPage能输出 current/size/total/pages。 - 再做XML 自定义分页:写一个带条件的 SQL(比如 age/name),确保
Page参数在第一位。 - 最后做乐观锁:复现“同时读—先后写”,观察第二次 update 返回 0,再加“失败重试”。