1. 配置分页插件
首先需要配置分页插件:
java
@Configuration
@MapperScan("com.example.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
// 设置请求的页面大于最大页后的操作,true调回到首页,false继续请求,默认false
paginationInterceptor.setOverflow(false);
// 设置单页限制数量,默认无限制
paginationInterceptor.setMaxLimit(500L);
// 设置数据库类型
paginationInterceptor.setDbType(DbType.MYSQL);
interceptor.addInnerInterceptor(paginationInterceptor);
return interceptor;
}
}
2. 基本使用方式
2.1 简单分页查询
java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 分页查询所有用户
public void pageQuery() {
// 参数1:当前页,参数2:每页条数
Page<User> page = new Page<>(1, 10);
Page<User> userPage = userMapper.selectPage(page, null);
System.out.println("总记录数:" + userPage.getTotal());
System.out.println("总页数:" + userPage.getPages());
System.out.println("当前页:" + userPage.getCurrent());
System.out.println("每页条数:" + userPage.getSize());
System.out.println("数据列表:" + userPage.getRecords());
}
}
2.2 条件分页查询
java
public void pageQueryWithCondition() {
Page<User> page = new Page<>(1, 10);
// 构建查询条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getStatus, 1)
.ge(User::getAge, 18)
.orderByDesc(User::getCreateTime);
Page<User> userPage = userMapper.selectPage(page, wrapper);
}
2.3 自定义分页方法
Mapper接口:
java
public interface UserMapper extends BaseMapper<User> {
// 自定义分页查询
Page<User> selectUserPage(Page<User> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper);
// 多表关联分页
Page<UserVO> selectUserWithRole(Page<UserVO> page, @Param("age") Integer age);
}
XML映射文件:
XML
<!-- 方式1:使用Wrapper -->
<select id="selectUserPage" resultType="com.example.entity.User">
SELECT * FROM user
${ew.customSqlSegment}
</select>
<!-- 方式2:多表关联 -->
<select id="selectUserWithRole" resultType="com.example.vo.UserVO">
SELECT u.*, r.role_name
FROM user u
LEFT JOIN user_role ur ON u.id = ur.user_id
LEFT JOIN role r ON ur.role_id = r.id
<where>
<if test="age != null">
AND u.age = #{age}
</if>
</where>
</select>
3. 高级特性
3.1 多表联查分页
java
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
public Page<OrderVO> getOrderPage(Integer current, Integer size, String userName) {
Page<OrderVO> page = new Page<>(current, size);
return orderMapper.selectOrderPage(page, userName);
}
}
XML
<!-- OrderMapper.xml -->
<select id="selectOrderPage" resultType="com.example.vo.OrderVO">
SELECT o.id, o.order_no, o.amount, u.user_name, u.phone
FROM orders o
LEFT JOIN user u ON o.user_id = u.id
<where>
<if test="userName != null and userName != ''">
AND u.user_name LIKE CONCAT('%', #{userName}, '%')
</if>
</where>
ORDER BY o.create_time DESC
</select>
3.2 分页结果封装
java
@Data
public class PageResult<T> {
private Long total;
private Long pages;
private Long current;
private Long size;
private List<T> records;
public static <T> PageResult<T> of(Page<T> page) {
PageResult<T> result = new PageResult<>();
result.setTotal(page.getTotal());
result.setPages(page.getPages());
result.setCurrent(page.getCurrent());
result.setSize(page.getSize());
result.setRecords(page.getRecords());
return result;
}
}
// 使用
PageResult<User> result = PageResult.of(userPage);
3.3 分页排序
java
// 方式1:通过Page对象排序
Page<User> page = new Page<>(1, 10);
page.addOrder(new OrderItem("age", true)); // 升序
page.addOrder(new OrderItem("create_time", false)); // 降序
// 方式2:通过Wrapper排序
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.orderByAsc(User::getAge)
.orderByDesc(User::getCreateTime);
Page<User> userPage = userMapper.selectPage(page, wrapper);
4. 性能优化建议
4.1 使用count优化
java
// 当数据量大时,可以控制是否查询总记录数
Page<User> page = new Page<>(1, 10);
page.setSearchCount(false); // 不查询总记录数,提升性能
// 或使用乐观锁优化
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
paginationInterceptor.setOptimizeJoin(true); // 优化join查询
4.2 避免N+1问题
java
// 不推荐:循环查询
List<User> users = userMapper.selectList(null);
for (User user : users) {
user.getOrders(); // 每次都会查询数据库
}
// 推荐:使用联表查询或批量查询
Page<UserOrderVO> page = new Page<>(1, 10);
Page<UserOrderVO> result = userMapper.selectUserWithOrders(page);
5. 完整示例
java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/page")
public Result<PageResult<User>> getUsers(
@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer minAge) {
Page<User> page = new Page<>(current, size);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.hasText(name), User::getName, name)
.ge(minAge != null, User::getAge, minAge)
.orderByDesc(User::getCreateTime);
Page<User> userPage = userService.page(page, wrapper);
return Result.success(PageResult.of(userPage));
}
}
6. 常见问题
| 问题 | 解决方案 |
|---|---|
| 分页不生效 | 检查是否配置了分页插件 |
| 总记录数为0 | 检查SQL是否正确,参数是否传递 |
| 分页位置错误 | 分页参数必须是第一个参数 |
| 内存溢出 | 检查是否设置了合理的分页大小 |
注意事项
-
分页参数必须是第一个参数(在自定义方法中)
-
必须配置分页插件,否则分页不生效
-
Page对象会自动处理总记录数,不需要手动count
-
多租户、逻辑删除等插件会与分页插件产生顺序影响