Appearance
MyBatis-Plus 分页插件
MyBatis-Plus 内置物理分页插件,一行配置即可实现分页查询,支持多表关联查询分页。
一、分页插件配置
java
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件
PaginationInnerInterceptor pagination = new PaginationInnerInterceptor();
// 数据库类型(MySQL)
pagination.setDbType(DbType.MYSQL);
// 单页最大条数限制(防止恶意查询)
pagination.setMaxLimit(500L);
// 溢出处理(超过总页数后默认回到首页)
pagination.setOverflow(true);
interceptor.addInnerInterceptor(pagination);
return interceptor;
}
}二、基础分页
2.1 BaseMapper 分页
java
// 创建分页对象
Page<User> page = new Page<>(1, 10); // 第 1 页,每页 10 条
// 无条件分页
Page<User> result = userMapper.selectPage(page, null);
System.out.println("总条数:" + result.getTotal());
System.out.println("总页数:" + result.getPages());
System.out.println("当前页:" + result.getCurrent());
System.out.println("数据:" + result.getRecords());
// 带条件分页
Page<User> result = userMapper.selectPage(
new Page<>(1, 10),
new LambdaQueryWrapper<User>()
.gt(User::getAge, 20)
.orderByDesc(User::getCreateTime)
);2.2 Service 层分页
java
// 方式一:Page 对象
Page<User> page = new Page<>(1, 10);
userService.page(page);
List<User> records = page.getRecords();
// 方式二:直接返回分页结果
IPage<User> result = userService.page(
new Page<>(1, 10),
new LambdaQueryWrapper<User>().gt(User::getAge, 20)
);
// 方式三:链式分页
IPage<User> result = userService.lambdaQuery()
.gt(User::getAge, 20)
.page(new Page<>(1, 10));三、自定义多表分页
3.1 Mapper 接口
java
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 自定义分页查询(多表关联)
IPage<UserVO> selectUserPage(Page<UserVO> page,
@Param("query") UserQuery query);
}3.2 Mapper XML
xml
<select id="selectUserPage" resultType="com.example.vo.UserVO">
SELECT u.id, u.name, u.age, o.order_no, o.amount
FROM user u
LEFT JOIN t_order o ON u.id = o.user_id
<where>
<if test="query.name != null and query.name != ''">
AND u.name LIKE CONCAT('%', #{query.name}, '%')
</if>
<if test="query.minAge != null">
AND u.age >= #{query.minAge}
</if>
</where>
ORDER BY u.create_time DESC
</select>java
// 调用
Page<UserVO> page = new Page<>(1, 10);
UserQuery query = new UserQuery();
query.setName("张");
IPage<UserVO> result = userMapper.selectUserPage(page, query);四、PageInfo 封装
java
// 分页查询
Page<User> page = new Page<>(1, 10);
userMapper.selectPage(page, null);
// 封装为 PageInfo(兼容 PageHelper 风格)
PageInfo<User> pageInfo = new PageInfo<>(page.getRecords());
// 或
PageInfo<User> pageInfo = PageInfo.of(page);
System.out.println("当前页:" + pageInfo.getPageNum());
System.out.println("页大小:" + pageInfo.getPageSize());
System.out.println("总条数:" + pageInfo.getTotal());
System.out.println("总页数:" + pageInfo.getPages());
System.out.println("是否有上一页:" + pageInfo.isHasPreviousPage());
System.out.println("是否有下一页:" + pageInfo.isHasNextPage());五、分页参数说明
java
// Page 构造方法
Page<T> page = new Page<>();
page.setCurrent(1); // 当前页(默认 1)
page.setSize(10); // 每页条数(默认 10)
page.setMaxLimit(500L); // 单页最大条数限制
page.setOptimizeCountSql(true); // 是否优化 COUNT SQL(默认 true)
page.setSearchCount(true); // 是否查询总数(默认 true)六、分页插件原理
MyBatis-Plus 分页原理:
① PaginationInnerInterceptor 拦截 Executor.query()
→ 检测到 Page 参数,进入分页逻辑
② 执行 COUNT 查询
→ 包装原始 SQL:SELECT COUNT(*) FROM (原始SQL) tmp
→ 获取总记录数
③ 计算分页参数
→ 总页数 = 总记录数 / 每页条数
→ 溢出处理:页码超出总页数时回到首页
④ 拼接分页 SQL
→ MySQL:原始 SQL + LIMIT offset, size
→ Oracle:嵌套查询 + ROWNUM
→ PostgreSQL:原始 SQL + LIMIT size OFFSET offset
⑤ 执行分页 SQL 返回结果七、速记总结
分页三步走:
① 配置分页插件(MybatisPlusInterceptor + PaginationInnerInterceptor)
② 创建 Page 对象(new Page<>(页码, 条数))
③ 调用 selectPage 或 page 方法
速记口诀:
插件配置一行起,Page 对象传页码,
selectPage 或 page 方法,自动拼 LIMIT 查总数。八、面试要点
| 问题 | 答案要点 |
|---|---|
| 分页怎么配置? | MybatisPlusInterceptor + PaginationInnerInterceptor |
| 自定义多表分页? | Mapper 方法第一个参数传 Page 对象 |
| 分页原理? | 拦截 Executor.query() → COUNT 查总数 → 拼接 LIMIT |
| 和 PageHelper 区别? | MP 内置分页,更原生,不需要 ThreadLocal |
