分页查询详细讲解

分页查询详细讲解

以下是 原生 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 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 queryEmpByPage(EmpQueryDTO dto) {

int pageNum = dto.getPageNum();

int pageSize = dto.getPageSize();

int offset = (pageNum - 1) * pageSize;

// 查询当前页数据

List data = empMapper.selectByPage(dto.getDeptId(), offset, pageSize);

// 查询总记录数

long total = empMapper.countTotal(dto.getDeptId());

return new PageResult<>(total, data);

}

// 3. 分页结果类

public class PageResult {

private long total;

private List list;

// 其他字段...

}

3. 优缺点

优点:无第三方依赖,灵活控制 SQL。缺点:需手动处理分页参数和总条数查询,代码冗余。

二、PageHelper 的 Page 对象

1. 实现步骤

启动分页:调用 PageHelper.startPage(pageNum, pageSize)。查询数据:直接执行查询,返回 Page(本质是 ArrayList 的子类)。获取分页数据:通过 Page 对象直接读取总记录数、当前页数据等。

2. 代码示例

// 1. Mapper 接口(无需分页参数)

public interface EmpMapper {

@Select("SELECT * FROM emp WHERE dept_id = #{deptId} ORDER BY id DESC")

List selectByCondition(@Param("deptId") Long deptId);

}

// 2. Service 层

public Page queryEmpByPage(EmpQueryDTO dto) {

PageHelper.startPage(dto.getPageNum(), dto.getPageSize());

List list = empMapper.selectByCondition(dto.getDeptId());

return (Page) list; // 强制转换为 Page 对象

}

// 3. Controller 层

@GetMapping("/emps")

public PageResult listEmps(EmpQueryDTO dto) {

Page page = empService.queryEmpByPage(dto);

return new PageResult<>(page.getTotal(), page.getResult());

}

3. 关键点

强制转换:Page 是 ArrayList 的子类,可以直接转换。分页元数据:Page 包含 total、pageNum、pageSize 等字段。

4. 优缺点

优点:简化分页参数处理,自动生成 COUNT 查询。缺点:需强制类型转换,返回的 Page 对象包含数据库方言细节。

三、PageHelper 的 PageInfo 对象

1. 实现步骤

启动分页:PageHelper.startPage(pageNum, pageSize)。查询数据:返回普通 List。封装结果:用 PageInfo 包裹 List,自动计算总页数、是否有下一页等。

2. 代码示例

// 1. Service 层

public PageInfo queryEmpByPage(EmpQueryDTO dto) {

PageHelper.startPage(dto.getPageNum(), dto.getPageSize());

List list = empMapper.selectByCondition(dto.getDeptId());

return new PageInfo<>(list);

}

// 2. Controller 层

@GetMapping("/emps")

public PageInfo listEmps(EmpQueryDTO dto) {

return empService.queryEmpByPage(dto);

}

3. PageInfo 核心字段

public class PageInfo {

private int pageNum; // 当前页码

private int pageSize; // 每页数量

private long total; // 总记录数

private int pages; // 总页数

private List list; // 当前页数据

private boolean hasNextPage; // 是否有下一页

// 其他字段...

}

4. 优缺点

优点:开箱即用,封装完整分页信息,无需手动转换。缺点:返回字段固定,若需自定义字段仍需二次封装。

四、三种方式对比

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

五、最佳实践建议

推荐 PageInfo:

适合大多数场景,减少重复代码,直接返回完整分页信息。示例:public PageInfo queryEmp(EmpQueryDTO dto) {

PageHelper.startPage(dto.getPageNum(), dto.getPageSize());

List list = empMapper.selectByCondition(dto.getDeptId());

return new PageInfo<>(list);

}

自定义分页实体类:

若前端需要特定字段名(如 current 代替 pageNum),可自定义 PageResult:public class PageResult {

@JsonProperty("current")

private int pageNum;

@JsonProperty("size")

private int pageSize;

private long total;

private List records;

}

性能优化:

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

参数校验:

int pageNum = dto.getPageNum() <= 0 ? 1 : dto.getPageNum();

int pageSize = dto.getPageSize() > 100 ? 100 : dto.getPageSize();

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

相关推荐

痰堵在支气管真吓人,8个方法教你有效排痰,赶紧收藏!
$上证指数(SH000001)$ 近几届世界杯国际足联的收入情况:
[大咖陪你看]刘畊宏VIP包间现场连线 分享观赛感受