> 技术文档 > 【Mybatis】分页插件及其原理

【Mybatis】分页插件及其原理


原理:

  1. 调用 mapper 接口的方法前,用 PageHelper 的静态方法 start 设置分页参数
  2. 分页参数会被存进 ThreadLocal 里面(这就是为什么要在调用 mapper 方法前设置参数的原因)。
  3. 调用 mapper 接口方法后,会在执行 sql 前进行拦截,拦截器检测出 ThreadLocal 中的分页参数,改写 sql 并添加分页条件。
  4. 新增一条 count(*)的 sql 语句执行
  5. 将结果封装成 Page 对象
  6. 后续可以利用 PageInfo 进行对 page 对象润色提供丰富的分页元数据
    包含以下关键信息:
    • total:总记录数
    • pages:总页数
    • pageNum:当前页码
    • pageSize:每页条数
    • list:当前页的数据列表
    • isFirstPage/isLastPage:是否为第一页 / 最后一页
    • hasPreviousPage/hasNextPage:是否有上一页 / 下一页

补充:为什么没有看见 mapper 接口的实现类:

是因为MyBatis 会在运行时通过 jdk 的动态代理自动生成接口的实现类

@Servicepublic class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public PageInfo findAll(int pageNum, int pageSize) { // 开始分页,pageNum是页码,pageSize是每页条数 PageHelper.startPage(pageNum, pageSize); // 执行查询 List users = userMapper.findAll(); // 封装分页结果 return new PageInfo(users); } @Override public PageInfo findByCondition(String username, int pageNum, int pageSize) { // 开始分页 PageHelper.startPage(pageNum, pageSize); // 执行带条件的查询 List users = userMapper.findByCondition(username); // 封装分页结果 return new PageInfo(users); }}

额外补充:

  1. users的特殊身份
    当调用PageHelper.startPage()后,MyBatis 执行查询返回的users集合,实际上是com.github.pagehelper.Page类型的实例(PageArrayList的子类)。
    这个Page对象内部已经包含了所有分页元数据:
    • 当前页码(pageNum
    • 每页条数(pageSize
    • 总记录数(total
    • 总页数(pages)等
  1. 也就是说,分页查询的所有关键信息已经提前存储在users对象中,并非PageInfo主动计算的。
  2. PageInfo的工作方式
    PageInfo的构造方法会对传入的users进行判断:
    • 如果是Page类型的集合,直接从中提取已有的分页元数据(pageNumtotal等)。
    • 基于这些元数据,自动计算出衍生信息:
      • isFirstPagepageNum == 1
      • isLastPagepageNum == pages
      • hasPreviousPagepageNum > 1
      • hasNextPagepageNum < pages
  1. 简单来说,PageInfo只是Page对象中已有的数据进行整理和封装,方便开发者使用,而不是重新计算分页信息。
  2. 元数据的来源
    这些分页元数据(总记录数、当前页码等)是怎么来的?
    • pageNumpageSize:来自PageHelper.startPage(pageNum, pageSize)的参数。
    • total(总记录数):PageHelper 拦截器会自动执行一条COUNT(*)语句查询得到。
    • pages(总页数):根据totalpageSize计算得出(pages = (total + pageSize - 1) / pageSize)。

这些数据会被 PageHelper 存入Page对象中,最终通过users集合传递给PageInfo