六、插件

29 阅读2分钟

分页插件、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 句话)

  1. 表里加 version 字段
  2. 取出数据时带上 version
  3. 更新时 version = version + 1,并且 where 里带 version,不匹配就更新失败

3.3 实操步骤

(1) 建表:加 version 列
讲义示例表:t_productVERSION

(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分钟一轮)

  1. 先把分页插件跑通:selectPage 能输出 current/size/total/pages。
  2. 再做XML 自定义分页:写一个带条件的 SQL(比如 age/name),确保 Page 参数在第一位。
  3. 最后做乐观锁:复现“同时读—先后写”,观察第二次 update 返回 0,再加“失败重试”。