PageHeper

PageHelper 是一个非常流行的 MyBatis 分页插件,主要用于简化分页查询的实现。使用 PageHelper 可以在执行数据库查询时,自动处理分页参数,从而避免手动编写繁琐的分页逻辑。

今天就来学习一下PageHelper的相关知识和用法!

PageHelper

主要功能

  1. 分页查询:通过 PageHelper.startPage() 方法指定页码和每页的大小,之后执行的查询会自动分页。
  2. 排序功能:支持排序功能,分页查询时可以通过指定排序字段和排序方式来获得排序后的结果集。
  3. 简化分页逻辑:无需手动修改 SQL 语句,PageHelper 会自动为查询 SQL 添加分页逻辑,大大简化代码。
  4. 多数据库支持PageHelper 支持多种主流的数据库,如 MySQL、Oracle、PostgreSQL 等。

使用步骤

  1. 引入依赖
    pom.xml 中添加 PageHelper 依赖:

    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.2.0</version>
    </dependency>
    
  2. 配置拦截器
    在 MyBatis 配置文件或配置类中,注册 PageHelper 拦截器:

    @Bean
    public PageInterceptor pageHelper() {
        PageInterceptor pageInterceptor = new PageInterceptor();
        Properties properties = new Properties();
        properties.setProperty("helperDialect", "mysql");  // 数据库类型
        pageInterceptor.setProperties(properties);
        return pageInterceptor;
    }
    
  3. 分页查询使用示例
    在代码中使用 PageHelper.startPage() 方法来指定分页参数,后续的查询会自动带上分页信息:

    @Service
    public class UserService {
    
        @Autowired
        private UserMapper userMapper;
    
        public List<User> getUsers(int pageNum, int pageSize) {
            // 开启分页
            PageHelper.startPage(pageNum, pageSize);
            // 查询结果
            return userMapper.getAllUsers();
        }
    }
    
  4. 返回分页结果
    使用 PageInfo 来包装分页结果,包含分页信息和查询结果:

    List<User> userList = userMapper.getAllUsers();
    PageInfo<User> pageInfo = new PageInfo<>(userList);
    System.out.println(pageInfo.getTotal());  // 总记录数
    System.out.println(pageInfo.getList());   // 当前页的记录列表
    

核心方法

  • PageHelper.startPage(int pageNum, int pageSize):指定页码和每页大小,之后的查询会自动分页。
  • PageHelper.orderBy(String orderBy):设置排序规则,如 "id desc",按 id 倒序排列。
  • PageInfo<T>:封装分页结果信息,包含总记录数、总页数、当前页的记录等。

总结

PageHelper 提供了一种简洁的方式来实现 MyBatis 的分页查询,自动处理分页逻辑并简化代码,同时支持多种数据库和排序功能,是 MyBatis 用户进行分页查询的一个常用工具。

SpringBoot中的PageHelper

pagehelper-spring-boot-starterPageHelper 的 Spring Boot 自动配置版本,能够更简便地集成 PageHelper,特别是在 Spring Boot 项目中。相比于手动配置 PageHelper,使用 pagehelper-spring-boot-starter 可以进一步简化配置和使用过程。

使用步骤

  1. 引入依赖
    在 Spring Boot 项目的 pom.xml 中添加 pagehelper-spring-boot-starter 依赖:

    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.4.6</version>
    </dependency>
    
  2. 自动配置
    引入 pagehelper-spring-boot-starter 后,不需要手动配置 PageHelper 拦截器,Spring Boot 会自动配置好分页插件。

  3. 在查询方法中使用
    使用 PageHelper.startPage() 方法指定分页参数,在执行查询时,结果会自动分页。

    示例代码:

    @Service
    public class UserService {
    
        @Autowired
        private UserMapper userMapper;
    
        // 分页获取用户列表
        public PageInfo<User> getUsers(int pageNum, int pageSize) {
            // 设置分页参数
            PageHelper.startPage(pageNum, pageSize);
            // 执行查询,得到结果集
            List<User> users = userMapper.getAllUsers();
            // 使用PageInfo来封装分页信息
            return new PageInfo<>(users);
        }
    }
    
  4. 返回分页结果
    PageInfoPageHelper 提供的工具类,用于封装分页信息,如总记录数、总页数、当前页数据等。可以通过 PageInfo 对象获取到这些信息:

    PageInfo<User> pageInfo = userService.getUsers(1, 10);
    System.out.println(pageInfo.getTotal());  // 获取总记录数
    System.out.println(pageInfo.getPages());  // 获取总页数
    System.out.println(pageInfo.getList());   // 获取当前页的数据
    
  5. 自定义配置(可选)
    你可以通过 Spring Boot 的 application.propertiesapplication.yml 文件自定义 PageHelper 的相关配置,比如数据库方言、合理化配置、分页方式等。

    application.yml 中添加自定义配置:

    pagehelper:
      helper-dialect: mysql  # 数据库方言
      reasonable: true       # 启用合理化,避免页码超出范围
      support-methods-arguments: true  # 支持分页参数作为方法参数
      params: count=countSql  # 分页查询时统计总数的SQL
    

    或者在 application.properties 中:

    pagehelper.helperDialect=mysql
    pagehelper.reasonable=true
    pagehelper.supportMethodsArguments=true
    pagehelper.params=count=countSql
    

复杂度

  • 时间复杂度:分页查询的时间复杂度依赖于数据库查询操作。一般情况下,查询复杂度为 $O(n)$,加上分页条件,实际执行时可能会根据数据库的索引和优化机制有所不同。
  • 空间复杂度:空间复杂度取决于分页结果和数据的存储形式,一般为 $O(k)$,其中 k 是每页返回的数据量。

总结

通过 pagehelper-spring-boot-starter,在 Spring Boot 项目中可以轻松集成 PageHelper,自动完成分页查询的配置和操作,简化了开发者的代码量。同时还支持自定义配置,能够灵活应对各种分页需求。

实际运用

在我正在写的仿12306项目中很多地方都会用到pagehelper,所以一般会封装分页查询的入参和出参类,就以查询乘车人为例:

PageReq

封装PageReq作为分页查询入参类的父类,为分页查询提供pageNumpageSize

PageReq
public class PageReq {

    @NotNull(message = "【页码】不能为空")
    private Integer start;

    @NotNull(message = "【每页条数】不能为空")
    @Max(value = 100, message = "【每页条数】不能超过100")
    private Integer count;

    public @NotNull(message = "【页码】不能为空") Integer getStart() {
        return start;
    }

    public void setStart(@NotNull(message = "【页码】不能为空") Integer start) {
        this.start = start;
    }

    public @NotNull(message = "【每页条数】不能为空") @Max(value = 100, message = "【每页条数】不能超过100") Integer getCount() {
        return count;
    }

    public void setCount(@NotNull(message = "【每页条数】不能为空") @Max(value = 100, message = "【每页条数】不能超过100") Integer count) {
        this.count = count;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("pageReq{");
        sb.append("start=").append(start);
        sb.append(", count=").append(count);
        sb.append('}');
        return sb.toString();
    }
}

查询乘车人服务的入参类继承PageReq类;

PassengerQueryReq
public class PassengerQueryReq extends PageReq {

    private Long memberId;

    private String idCard;

    public Long getMemberId() {
        return memberId;
    }

    public void setMemberId(Long memberId) {
        this.memberId = memberId;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("PassengerQueryReq{");
        sb.append("memberId=").append(memberId);
        sb.append(", idCard='").append(idCard).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

在查询乘车人服务中使用PageReq提供的pageNumpageSize调用PageHelper

PassengerService
@Service
public class PassengerService {

    @Resource
    private PassengerMapper passengerMapper;

    public List<PassengerQueryResp> queryList (PassengerQueryReq req) {
        PassengerExample passengerExample = new PassengerExample();
        PassengerExample.Criteria criteria = passengerExample.createCriteria();
        if (ObjectUtil.isNotNull(req.getMemberId())) {
            criteria.andMemberIdEqualTo(req.getMemberId());
        }
        PageHelper.startPage(req.getStart(), req.getCount());
        List<Passenger> passengerList = passengerMapper.selectByExample(passengerExample);
        return BeanUtil.copyToList(passengerList, PassengerQueryResp.class);
    }

    public void update(PassengerSaveReq req) {
        DateTime now = DateTime.now();
        Passenger passenger = BeanUtil.copyProperties(req, Passenger.class);
        passenger.setMemberId(LoginMemberContext.getId());
        passenger.setModifiedTime(now);

        PassengerExample passengerExample = new PassengerExample();
        passengerExample.createCriteria().
                andMemberIdEqualTo(passenger.getMemberId()).
                andIdCardEqualTo(passenger.getIdCard());

        passengerMapper.updateByExampleSelective(passenger, passengerExample);
    }
}

PageResp

封装PageResp作为response类,返回查询总数、分页总数和查询列表;

PageResp
public class PageResp<T> implements Serializable {

    private static final Long serialVersionUID = 1L;

    /**
     * 查询结果总数
     */
    private Long total;

    /**
     * 查询结果列表
     */
    private List<T> list;

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public Long getTotal() {
        return total;
    }

    public void setTotal(Long total) {
        this.total = total;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("PageResp{");
        sb.append("total=").append(total);
        sb.append(", list=").append(list);
        sb.append('}');
        return sb.toString();
    }
}

查询乘车人服务中使用PageInfo获取分页查询的结果总数和分页数,返回PageResp

PassengerService
@Service
public class PassengerService {

    private static final Logger LOG = LoggerFactory.getLogger(PassengerService.class);

    @Resource
    private PassengerMapper passengerMapper;

    public PageResp<PassengerQueryResp> queryList (PassengerQueryReq req) {
        PassengerExample passengerExample = new PassengerExample();
        PassengerExample.Criteria criteria = passengerExample.createCriteria();
        if (ObjectUtil.isNotNull(req.getMemberId())) {
            criteria.andMemberIdEqualTo(req.getMemberId());
        }

        // mybatis PageHelper分页查询
        LOG.info("查询页码:{}", req.getStart());
        LOG.info("每页条数:{}", req.getCount());
        PageHelper.startPage(req.getStart(), req.getCount());
        List<Passenger> passengerList = passengerMapper.selectByExample(passengerExample);
        // 把passengerList转为passengerQueryRespList
        List<PassengerQueryResp> passengerQueryResp = BeanUtil.copyToList(passengerList, PassengerQueryResp.class);

        // pageHelper获取分页查询总条数,将分页查询结果(条数+list)封装到pageResp
        PageInfo<Passenger> pageInfo = new PageInfo<>(passengerList);
        LOG.info("总条数:{}", pageInfo.getTotal());
        LOG.info("总页数:{}", pageInfo.getPages());
        PageResp<PassengerQueryResp> pageResp = new PageResp<>();
        pageResp.setList(passengerQueryResp);
        pageResp.setTotal(pageInfo.getTotal());
        return pageResp;
    }
}
posted @ 2024-09-05 17:20  鱼摆摆不摆  阅读(16)  评论(0编辑  收藏  举报