# 【一看就会】分页查询剖析 + 分页插件-pageHelper

分页算法

# 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);
  • 作用:
    • 使用 PageHelperstartPage 方法设置分页参数。
    • 拦截下面的 SQL 查询,在其结果中自动添加分页逻辑,比如设置 LIMITOFFSET
    • pagepageSize 分别决定当前页和每页的行数。

执行查询

List<Emp> empList = empMapper.list(name, gender, begin, end);
  • 调用数据访问层:
    • 执行查询,传入过滤条件(namegenderbeginend)。
    • 返回值是一个 List<Emp>,即员工数据列表。

封装到 PageBean

PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
  • PageBean 上文中的 自定义分页对象:
    • p.getTotal(): 获取总记录数。
    • p.getResult(): 获取当前页的结果集。
  • 这一步将分页数据和结果列表封装到一个 PageBean 对象中。

返回结果

return pageBean;
  • 返回封装好的分页数据给前端展示或继续处理。

End

如果这篇文章帮到你, 帮忙点个关注呗, 点赞或收藏也行鸭 ~ (。•ᴗ-)✧

在这里插入图片描述
^ '(இ﹏இ`。)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值