分页算法
# MySQL 一切分页算法都基于以下 sql 实现
offset rows
select ... from table limit(从哪里, 要多少)
-
currentPage
: 表示用户点击的当前页码。用于计算出 offset (偏移量) 即跳过的行数, 从哪里开始截取-
offset
计算公式 : (currentPage - 1) * pageSize
用户翻页时 offset 的动态展示 :用户点页码时 offset 描述 用户点击第1页时 (1 - 1) * 10 = 0 从0基索引行开始查询 用户点击第2页时 (2 - 1) * 10 = 10 从第10行开始查询 用户点击第3页时 (3 - 1) * 10 = 20 从第20行开始查询
场景
select * from user limit (offset 起始页, 返回几行) // 用户进入页面时 查询第一页, 返回十行, 显示第一行到第十行的数据 select * from user limit (0, 10) // 用户点击第二页 查询第二页, 返回十行, 显示第11行到第20行的数据 select * from user limit (10, 10) // 用户点击第三页 查询第三页, 返回十行, 显示为从第21行到第30行的数据 select * from user limit (20, 10)
-
-
pageSize
: 每页显示的行数。用来计算所有数据的总页数 totalPage, 例如: 每行显示十条数据, 总共有两百条, 那么总页数
为 20-
计算公式 :
totalPages = ceil(totalCount / pageSize)
( 向上取整为了确保最后一页显示剩余的记录。) -
为什么要向上取整, 例 : 如果总共有 51 行数据, 使用公式就是 51 / 10 =
5.1
, 如果四舍五入
就代表只有5页
, 也就是说第 51 条数据就不会显示。所以正常来讲, 应该是总共有
6页
,第6页
仅显示一条数据, 为了满足这个需求, 则使用向上取整,
这样 51 就被取整成了 60, 原本的 5 页, 就变成了 6 页
-
-
totalCount
: 总共有多少行数据/总记录数。也是用来计算所有数据的总页数, -
totalPages
: 总页数。 -
data
: 当前页的数据列表
引入依赖
分页插件 pagehelper
<!--分页查询插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.7</version>
</dependency>
确保引入了 springboot 起步依赖, 其中包含 日志打印相关间接依赖, 可选择
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
实体层
package com.doth.mybatiscase.pojo; //换成自己的包哦
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 分页查询结果封装类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {
private Long total; //总记录数
private List rows; //返回的数据
}
控制层
场景 : 查询员工
package com.doth.mybatiscase.controller; //报错的都要换成自己的包哦
import com.doth.mybatiscase.pojo.Emp;
import com.doth.mybatiscase.pojo.PageBean;
import com.doth.mybatiscase.pojo.Result;
import com.doth.mybatiscase.service.EmpService;
import com.doth.mybatiscase.service.impl.EmpServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.List;
@RequestMapping("/emps") // 公共路径
@Slf4j
@RestController
public class EmpController {
// 注入service 对象
@Autowired
private EmpService empService;
/**
* 分页查询
* @param page 当前页码
* @param pageSize 每页记录数
* @param name 姓名
* @param gender 性别
* @param begin 入职时间
* @param end 离职时间
* @return 结果集对象
*/
@GetMapping()
// 注解方式设置默认值
Result page(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
String name, Short gender,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
log.info("\n分页查询, 参数: {}, {}, {}, {}, {}, {}",page,pageSize,name,gender,begin,end);
PageBean pageBean = empService.page(page,pageSize,name,gender,begin,end);
return Result.success(pageBean);
}
}
数据访问层 mapper
package com.doth.mybatiscase.mapper; //改成自己的包哦
import com.doth.mybatiscase.pojo.Emp;
import org.apache.ibatis.annotations.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Mapper
public interface EmpMapper {
/**
* 员工查询
* @return
*/
// 导入pagehelper 依赖后, 直接select * from emp 查询即可, 但是要处理过滤条件, 所以写入了 xml 文件中
List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);
}
mapper list方法对应的 xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mybatis 定义的 xml 语法规则, 不需要去理解, 直接复制-->
<mapper namespace="com.doth.mybatiscase.mapper.EmpMapper"> <!-- 换成自己的包哦 -->
<!--方法名list-->
<select id="list" resultType="com.doth.mybatiscase.pojo.Emp"> <!--返回你的实体的全类名-->
select *
from emp
<where>
<if test="name != null and name != ''">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
</mapper>
事务层 service
package com.doth.mybatiscase.service.impl;
import com.doth.mybatiscase.mapper.EmpMapper;
import com.doth.mybatiscase.pojo.Emp;
import com.doth.mybatiscase.pojo.PageBean;
import com.doth.mybatiscase.service.EmpService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public PageBean page(Integer page, Integer pageSize,
String name, Short gender,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {\\
// 设置分页参数
PageHelper.startPage(page, pageSize);
// 执行查询
List<Emp> empList = empMapper.list(name, gender, begin, end);
Page<Emp> p = (Page<Emp>) empList; // 直接强转page类型
// 将结果封装到 PageBean
PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
return pageBean;
}
}
逐步解析
PageHelper.startPage(page, pageSize);
- 作用:
- 使用 PageHelper 的
startPage
方法设置分页参数。 - 拦截下面的 SQL 查询,在其结果中自动添加分页逻辑,比如设置
LIMIT
和OFFSET
。 page
和pageSize
分别决定当前页和每页的行数。
- 使用 PageHelper 的
执行查询
List<Emp> empList = empMapper.list(name, gender, begin, end);
- 调用数据访问层:
- 执行查询,传入过滤条件(
name
、gender
、begin
、end
)。 - 返回值是一个
List<Emp>
,即员工数据列表。
- 执行查询,传入过滤条件(
封装到 PageBean
PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
PageBean
上文中的 自定义分页对象:p.getTotal()
: 获取总记录数。p.getResult()
: 获取当前页的结果集。
- 这一步将分页数据和结果列表封装到一个
PageBean
对象中。
返回结果
return pageBean;
- 返回封装好的分页数据给前端展示或继续处理。
End
如果这篇文章帮到你, 帮忙点个关注呗, 点赞或收藏也行鸭 ~ (。•ᴗ-)✧
^ '(இ﹏இ`。)