一、环境准备
- 添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
- 配置分页插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
paginationInterceptor.setDbType(DbType.MYSQL); // 设置数据库类型
paginationInterceptor.setOverflow(true); // 超出总页数后返回第一页
interceptor.addInnerInterceptor(paginationInterceptor);
return interceptor;
}
}
二、基础分页使用
- 简单分页查询
// 创建分页对象(查询第2页,每页10条)
Page<User> page = new Page<>(2, 10);
// 执行分页查询
Page<User> result = userMapper.selectPage(page, null);
// 获取结果
List<User> users = result.getRecords(); // 当前页数据
long total = result.getTotal(); // 总记录数
long pages = result.getPages(); // 总页数
- 带条件分页查询
/ 创建查询条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "张")
.gt("age", 18);
// 创建分页对象
Page<User> page = new Page<>(1, 5);
// 执行查询
Page<User> result = userMapper.selectPage(page, queryWrapper);
三、自定义SQL分页
- Mapper接口定义
public interface UserMapper extends BaseMapper<User> {
// 方法1:使用@Select注解
@Select("SELECT * FROM user WHERE status = #{status}")
Page<User> selectByStatus(Page<User> page, @Param("status") Integer status);
// 方法2:XML配置
Page<User> selectComplexPage(Page<User> page, @Param("param") Map<String, Object> params);
}
2. XML配置示例
xml
<!-- resources/mapper/UserMapper.xml -->
<select id="selectComplexPage" resultType="User">
SELECT * FROM user
WHERE age > #{param.minAge}
AND create_time > #{param.startDate}
ORDER BY create_time DESC
</select>
3. Service层调用
java
public Page<User> getActiveUsers(int page, int size) {
Page<User> pageParam = new Page<>(page, size);
return userMapper.selectByStatus(pageParam, 1);
}
四、分页结果处理
- 获取分页数据
Page<User> result = userService.page(new Page<>(1, 10));
// 获取数据列表
List<User> records = result.getRecords();
// 获取分页信息
long current = result.getCurrent(); // 当前页
long size = result.getSize(); // 每页大小
long total = result.getTotal(); // 总记录数
long pages = result.getPages(); // 总页数
2. 转换VO对象
java
public Page<UserVO> getUserVOPage(int page, int size) {
Page<User> userPage = userService.page(new Page<>(page, size));
// 转换分页结果
return userPage.convert(user -> {
UserVO vo = new UserVO();
vo.setId(user.getId());
vo.setName(user.getName());
vo.setAge(user.getAge());
return vo;
});
}
五、高级功能
- 不分页但获取总数
Page<User> page = new Page<>(1, -1); // size设为-1表示不分页
Page<User> result = userMapper.selectPage(page, null);
List<User> allUsers = result.getRecords(); // 所有数据
long total = result.getTotal(); // 总数
2. 自定义COUNT语句
java
@Select("SELECT * FROM user WHERE dept_id = #{deptId}")
@Options(countSql = "SELECT COUNT(1) FROM user WHERE dept_id = #{deptId}")
Page<User> selectByDept(Page<User> page, @Param("deptId") Long deptId);
- 多表关联分页优化
public Page<UserDTO> getUserWithDept(int page, int size) {
Page<User> userPage = new Page<>(page, size);
userMapper.selectPage(userPage, null);
// 提取用户ID
List<Long> userIds = userPage.getRecords().stream()
.map(User::getId)
.collect(Collectors.toList());
// 批量查询部门信息
Map<Long, Dept> deptMap = deptService.getDeptMapByUserIds(userIds);
// 转换DTO
return userPage.convert(user -> {
UserDTO dto = new UserDTO();
BeanUtils.copyProperties(user, dto);
dto.setDeptName(deptMap.get(user.getDeptId()).getName());
return dto;
});
}
六、最佳实践
- Controller层统一分页响应
@GetMapping("/users")
public R<PageData<UserVO>> listUsers(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
Page<UserVO> result = userService.getUserVOPage(page, size);
// 封装统一响应格式
PageData<UserVO> data = new PageData<>();
data.setList(result.getRecords());
data.setTotal(result.getTotal());
data.setPage(result.getCurrent());
data.setPageSize(result.getSize());
data.setPages(result.getPages());
return R.ok(data);
}
2. 分页参数封装
java
@Data
public class PageParam {
@Min(1)
private int page = 1;
@Range(min = 1, max = 100)
private int size = 10;
private String sortField;
private SortOrder sortOrder;
public <T> Page<T> buildPage() {
Page<T> page = new Page<>(this.page, this.size);
// 添加排序
if (sortField != null && sortOrder != null) {
if (sortOrder == SortOrder.ASC) {
page.addOrder(OrderItem.asc(sortField));
} else {
page.addOrder(OrderItem.desc(sortField));
}
}
return page;
}
public enum SortOrder {
ASC, DESC
}
}
性能优化建议 避免大表COUNT:
java // 对于超大数据集,关闭自动COUNT Page page = new Page<>(1, 10, false);
索引优化:sql
– 确保分页字段有索引 CREATE INDEX idx_create_time ON user(create_time);
深度分页优化:
// 使用游标分页替代传统分页
Cursor<User> cursor = userMapper.selectCursor(
new QueryWrapper<User>().gt("id", lastId).orderByAsc("id"),
new Cursor<>(lastId, 10)
);
七、常见问题解决
- 分页失效问题 原因:未配置分页插件或配置不正确 解决:
检查 @Configuration 类中的插件配置
确保 PaginationInnerInterceptor 已添加到拦截器
- 查询第二页返回第一页数据 原因:错误使用 setPages() 而不是 setCurrent()
正确用法:
java
Page<User> page = new Page<>();
page.setCurrent(2); // 设置当前页码
page.setSize(10);
- 自定义SQL分页无效
原因:XML中的SQL未正确处理分页参数
正确配置:
<select id="selectUsers" resultType="User">
SELECT * FROM user</select>
<!-- 不需要手动写LIMIT,插件会自动处理 -->
4. 排序失效
正确用法:
Page<User> page = new Page<>(1, 10);
page.addOrder(OrderItem.desc("create_time")); // 添加排序条件
八、完整示例项目结构
src/main/java
├── com.example
│ ├── config
│ │ └── MybatisPlusConfig.java # 配置类
│ ├── controller
│ │ └── UserController.java # 控制器
│ ├── entity
│ │ └── User.java # 实体类
│ ├── mapper
│ │ └── UserMapper.java # Mapper接口
│ ├── service
│ │ ├── UserService.java # 服务接口
│ │ └── impl
│ │ └── UserServiceImpl.java # 服务实现
│ └── dto
│ ├── PageParam.java # 分页参数
│ └── PageData.java # 分页响应
resources
└── mapper
└── UserMapper.xml # SQL映射文件
提示:在实际项目中,建议将分页参数处理和响应封装提取到公共模块,保持代码统一性。
通过本指南,您可以全面掌握MyBatis-Plus分页功能,从基础使用到高级优化,解决常见问题,构建高效的分页查询系统。
生成mybatisplus 分页极速使用指南 用markdown格式输出
我们创建一个极速使用指南,重点突出最常用、最核心的步骤,去除冗余说明,让开发者能快速上手。
指南包括:环境准备、基本使用、自定义SQL分页、常见问题。
注意:使用Markdown格式
MyBatis-Plus 分页极速使用指南
只需3步完成高效分页开发
一、极速配置(30秒)
- 添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
- 配置分页插件
@Configuration
public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
二、核心使用(3种场景)
场景1:基础分页查询
// 创建分页对象(第2页,每页10条)
Page<User> page = new Page<>(2, 10);
// 执行查询(无条件)
Page<User> result = userMapper.selectPage(page, null);
// 获取结果
List<User> users = result.getRecords(); // 当前页数据
long total = result.getTotal(); // 总记录数
场景2:带条件分页
// 创建查询条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name", "张").gt("age", 18);
// 执行分页查询
Page<User> result = userMapper.selectPage(new Page<>(1, 5), wrapper);
场景3:自定义SQL分页
java
// Mapper接口
@Select("SELECT * FROM user WHERE status = #{status}")
Page<User> selectByStatus(Page<User> page, @Param("status") Integer status);
// Service调用
Page<User> result = userMapper.selectByStatus(new Page<>(1, 10), 1);
三、进阶技巧(高效开发)
- 分页参数自动封装
@Data
public class PageParam {
private int page = 1;
private int size = 10;
public <T> Page<T> buildPage() {
return new Page<>(page, size);
}
}
// Controller使用
@GetMapping("/users")
public PageData<User> listUsers(PageParam pageParam) {
return userService.getPageData(pageParam.buildPage());
}
- 分页结果转换
public Page<UserVO> convertToVO(Page<User> userPage) {
return userPage.convert(user -> {
UserVO vo = new UserVO();
BeanUtils.copyProperties(user, vo);
return vo;
});
}
- 深度分页优化(百万数据)
// 方法1:游标分页
Cursor<User> cursor = userMapper.selectCursor(
new QueryWrapper<User>().gt("id", lastId),
new Cursor<>(lastId, 100)
);
// 方法2:ID范围查询
List<User> users = userMapper.selectList(
new QueryWrapper<User>()
.gt("id", lastId)
.orderByAsc("id")
.last("LIMIT 100")
);
四、避坑指南
- 分页失效检查清单 ✅ 是否配置了PaginationInnerInterceptor
✅ 是否使用new Page<>(pageNum, pageSize)创建对象
✅ 自定义SQL是否返回Page类型
- 高频错误解决方案
// 错误:查询总是返回第一页
Page<User> page = new Page<>();
page.setCurrent(2); // 必须设置当前页!
page.setSize(10);
// 错误:排序失效
Page<User> page = new Page<>(1, 10);
page.addOrder(OrderItem.desc("create_time")); // 添加排序
五、最佳实践
Controller层标准写法
@GetMapping("/page")
public R<PageData<UserVO>> getUserPage(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
Page<User> pageParam = new Page<>(page, size);
Page<UserVO> result = userService.getUserPage(pageParam);
return R.ok(PageData.from(result));
}
PageData响应封装
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageData<T> {
private List<T> list;
private long total;
private long page;
private long size;
private long pages;
public static <T> PageData<T> from(Page<T> page) {
return new PageData<>(
page.getRecords(),
page.getTotal(),
page.getCurrent(),
page.getSize(),
page.getPages()
);
}
}
效率提示:使用此指南可节省80%的分页开发时间!实际项目只需复制对应代码片段修改即可。