分页查询详细讲解

以下是 原生 SQL 分页PageHelper 的 Page 对象PageInfo 对象 三种分页查询方式的详细实现讲解,包含代码示例和对比分析。


一、原生 SQL 分页(不依赖 PageHelper)

1. 实现步骤
  • SQL 分页语法:手动编写 LIMIT offset, pageSize
  • 总记录数查询:单独编写 COUNT(*) SQL。
  • 参数计算:手动计算 offset = (pageNum - 1) * pageSize
2. 代码示例
// 1. Mapper 接口
public interface EmpMapper {
    // 分页查询数据
    @Select("SELECT * FROM emp WHERE dept_id = #{deptId} ORDER BY id DESC LIMIT #{offset}, #{pageSize}")
    List<Emp> selectByPage(@Param("deptId") Long deptId, @Param("offset") int offset, @Param("pageSize") int pageSize);

    // 查询总记录数
    @Select("SELECT COUNT(*) FROM emp WHERE dept_id = #{deptId}")
    long countTotal(@Param("deptId") Long deptId);
}

// 2. Service 层
public PageResult<Emp> queryEmpByPage(EmpQueryDTO dto) {
    int pageNum = dto.getPageNum();
    int pageSize = dto.getPageSize();
    int offset = (pageNum - 1) * pageSize;

    // 查询当前页数据
    List<Emp> data = empMapper.selectByPage(dto.getDeptId(), offset, pageSize);
    
    // 查询总记录数
    long total = empMapper.countTotal(dto.getDeptId());
    
    return new PageResult<>(total, data);
}

// 3. 分页结果类
public class PageResult<T> {
    private long total;
    private List<T> list;
    // 其他字段...
}
3. 优缺点
  • 优点:无第三方依赖,灵活控制 SQL。
  • 缺点:需手动处理分页参数和总条数查询,代码冗余。

二、PageHelper 的 Page 对象

1. 实现步骤
  • 启动分页:调用 PageHelper.startPage(pageNum, pageSize)
  • 查询数据:直接执行查询,返回 Page<T>(本质是 ArrayList 的子类)。
  • 获取分页数据:通过 Page<T> 对象直接读取总记录数、当前页数据等。
2. 代码示例
// 1. Mapper 接口(无需分页参数)
public interface EmpMapper {
    @Select("SELECT * FROM emp WHERE dept_id = #{deptId} ORDER BY id DESC")
    List<Emp> selectByCondition(@Param("deptId") Long deptId);
}

// 2. Service 层
public Page<Emp> queryEmpByPage(EmpQueryDTO dto) {
    PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
    List<Emp> list = empMapper.selectByCondition(dto.getDeptId());
    return (Page<Emp>) list;  // 强制转换为 Page 对象
}

// 3. Controller 层
@GetMapping("/emps")
public PageResult<Emp> listEmps(EmpQueryDTO dto) {
    Page<Emp> page = empService.queryEmpByPage(dto);
    return new PageResult<>(page.getTotal(), page.getResult());
}
3. 关键点
  • 强制转换Page<T>ArrayList 的子类,可以直接转换。
  • 分页元数据Page<T> 包含 totalpageNumpageSize 等字段。
4. 优缺点
  • 优点:简化分页参数处理,自动生成 COUNT 查询。
  • 缺点:需强制类型转换,返回的 Page 对象包含数据库方言细节。

三、PageHelper 的 PageInfo 对象

1. 实现步骤
  • 启动分页PageHelper.startPage(pageNum, pageSize)
  • 查询数据:返回普通 List<T>
  • 封装结果:用 PageInfo 包裹 List<T>,自动计算总页数、是否有下一页等。
2. 代码示例
// 1. Service 层
public PageInfo<Emp> queryEmpByPage(EmpQueryDTO dto) {
    PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
    List<Emp> list = empMapper.selectByCondition(dto.getDeptId());
    return new PageInfo<>(list);
}

// 2. Controller 层
@GetMapping("/emps")
public PageInfo<Emp> listEmps(EmpQueryDTO dto) {
    return empService.queryEmpByPage(dto);
}
3. PageInfo 核心字段
public class PageInfo<T> {
    private int pageNum;         // 当前页码
    private int pageSize;        // 每页数量
    private long total;          // 总记录数
    private int pages;           // 总页数
    private List<T> list;        // 当前页数据
    private boolean hasNextPage; // 是否有下一页
    // 其他字段...
}
4. 优缺点
  • 优点:开箱即用,封装完整分页信息,无需手动转换。
  • 缺点:返回字段固定,若需自定义字段仍需二次封装。

四、三种方式对比

维度原生 SQL 分页PageHelper + PagePageHelper + PageInfo
依赖PageHelper 插件PageHelper 插件
代码量多(手动处理分页逻辑)中等(需类型转换)少(直接返回 PageInfo
分页信息需手动封装包含基本分页字段(total、list)包含完整分页字段(pages、hasNext等)
灵活性高(可完全控制 SQL)中(依赖插件自动分页)低(字段固定)
适用场景简单分页或禁用第三方库时需要快速实现分页需要完整分页信息且减少代码

五、最佳实践建议

  1. 推荐 PageInfo

    • 适合大多数场景,减少重复代码,直接返回完整分页信息。
    • 示例:
      public PageInfo<Emp> queryEmp(EmpQueryDTO dto) {
          PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
          List<Emp> list = empMapper.selectByCondition(dto.getDeptId());
          return new PageInfo<>(list);
      }
      
  2. 自定义分页实体类

    • 若前端需要特定字段名(如 current 代替 pageNum),可自定义 PageResult
      public class PageResult<T> {
          @JsonProperty("current")
          private int pageNum;
          @JsonProperty("size")
          private int pageSize;
          private long total;
          private List<T> records;
      }
      
  3. 性能优化

    • 大数据量分页时,在 startPage 中指定 count 优化:
      PageHelper.startPage(pageNum, pageSize, "COUNT(id)");
      
  4. 参数校验

    int pageNum = dto.getPageNum() <= 0 ? 1 : dto.getPageNum();
    int pageSize = dto.getPageSize() > 100 ? 100 : dto.getPageSize();
    

通过以上三种方式,可根据项目需求灵活选择分页实现方案!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值