PageHelp插件使用
PageHelp插件使用
一、PageHelper 是什么?
PageHelper 是 MyBatis 的一个开源分页插件,它通过拦截 MyBatis 执行的 SQL 语句,自动在原SQL上添加分页语句(如 MySQL 的 LIMIT),并同时查询总记录数。
核心特点:
- 简单易用:只需要一行代码即可实现分页
- 支持多种数据库:MySQL、Oracle、PostgreSQL、SQLServer 等
- 零侵入:不需要修改原有Mapper和SQL语句
- 功能丰富:支持多种分页方式、排序、Count查询优化等
二、为什么要用 PageHelper?
在没有分页插件时,我们需要手动写分页SQL:
-- 传统方式需要写两条SQL
SELECT COUNT(*) FROM users WHERE age > 18; -- 查询总数
SELECT * FROM users WHERE age > 18 LIMIT 0, 10; -- 查询数据
PageHelper 的优势:
- 代码简洁:一行代码代替复杂的分页逻辑
- 维护方便:分页逻辑与业务逻辑分离
- 功能强大:自动处理总数统计、页码计算等
- 性能优化:支持多种 Count 查询优化策略
三、集成与配置
1. 添加依赖
Maven 项目:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
Gradle 项目:
implementation 'com.github.pagehelper:pagehelper-spring-boot-starter:1.4.2'
2. 配置文件(application.yml)
pagehelper:
helper-dialect: mysql # 数据库方言:mysql, oracle, postgresql 等
reasonable: true # 分页合理化:true时,pageNum<=0会查询第一页,pageNum>总页数会查询最后一页
support-methods-arguments: true # 支持通过Mapper接口参数来传递分页参数
params: count=countSql # 用于从Map或ServletRequest中参数名的映射
page-size-zero: false # 当pageSize=0时返回所有结果
四、核心使用方法
1. 基本分页查询
这是最常用的方式,在查询方法前调用 PageHelper.startPage():
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
/**
* 分页查询用户列表
*/
public PageInfo<User> getUsersByPage(int pageNum, int pageSize) {
// 关键代码:在查询方法前调用,第一个参数是页码,第二个是每页大小
PageHelper.startPage(pageNum, pageSize);
// 正常的查询,不需要任何修改
List<User> userList = userMapper.selectAllUsers();
// 用PageInfo对结果进行包装,PageInfo包含了丰富的分页信息
PageInfo<User> pageInfo = new PageInfo<>(userList);
return pageInfo;
}
}
2. Mapper 接口和 XML
UserMapper.java:
@Mapper
public interface UserMapper {
List<User> selectAllUsers();
List<User> selectUsersByCondition(UserQuery query);
}
UserMapper.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">
<mapper namespace="com.example.mapper.UserMapper">
<!-- 正常的查询SQL,不需要任何分页语句 -->
<select id="selectAllUsers" resultType="User">
SELECT id, name, age, email FROM users
</select>
<select id="selectUsersByCondition" parameterType="UserQuery" resultType="User">
SELECT id, name, age, email FROM users
WHERE 1=1
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="minAge != null">
AND age >= #{minAge}
</if>
<if test="maxAge != null">
AND age <= #{maxAge}
</if>
</select>
</mapper>
3. 实体类
// 用户实体
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
// 查询条件实体
@Data
public class UserQuery {
private String name;
private Integer minAge;
private Integer maxAge;
}
五、PageInfo 对象详解
PageInfo 对象包含了完整的分页信息,非常适合返回给前端:
// 测试分页查询
@Test
public void testPageInfo() {
PageHelper.startPage(2, 5); // 查询第2页,每页5条
List<User> userList = userMapper.selectAllUsers();
PageInfo<User> pageInfo = new PageInfo<>(userList);
// 打印分页信息
System.out.println("当前页: " + pageInfo.getPageNum());
System.out.println("每页大小: " + pageInfo.getPageSize());
System.out.println("当前页数据: " + pageInfo.getList());
System.out.println("总记录数: " + pageInfo.getTotal());
System.out.println("总页数: " + pageInfo.getPages());
System.out.println("是否是第一页: " + pageInfo.isIsFirstPage());
System.out.println("是否是最后一页: " + pageInfo.isIsLastPage());
System.out.println("是否有上一页: " + pageInfo.isHasPreviousPage());
System.out.println("是否有下一页: " + pageInfo.isHasNextPage());
}
PageInfo 常用属性:
list:分页后的数据列表pageNum:当前页码pageSize:每页显示数量total:总记录数pages:总页数prePage:上一页页码nextPage:下一页页码isFirstPage/isLastPage:是否第一页/最后一页hasPreviousPage/hasNextPage:是否有上一页/下一页navigatePages:导航页码数(默认8)navigatepageNums:所有导航页号
六、多种使用方式
1. 方式一:startPage + PageInfo(推荐)
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectByExample(example);
PageInfo<User> pageInfo = new PageInfo<>(list);
2. 方式二:使用Page对象
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectByExample(example);
PageInfo<User> pageInfo = new PageInfo<>(list);
// 或者直接使用Page对象
Page<User> page = (Page<User>) list;
System.out.println("总数: " + page.getTotal());
3. 方式三:使用Mapper接口参数(需要配置)
// 在接口方法中添加RowBounds参数
List<User> selectByRowBounds(UserExample example, RowBounds rowBounds);
// 使用
List<User> list = userMapper.selectByRowBounds(
example, new RowBounds(0, 10));
七、高级功能
1. 排序功能
// 单字段排序
PageHelper.startPage(1, 10, "id desc");
// 多字段排序
PageHelper.startPage(1, 10, "age asc, name desc");
// 或者使用OrderBy
PageHelper.startPage(1, 10)
.setOrderBy("create_time desc");
2. 复杂查询条件 + 分页
public PageInfo<User> searchUsers(UserQuery query, int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<User> userList = userMapper.selectUsersByCondition(query);
return new PageInfo<>(userList);
}
3. 只分页不查询总数(提升性能)
// 第三个参数设为false,不执行count查询
PageHelper.startPage(1, 10, false);
List<User> list = userMapper.selectAllUsers();
八、完整实战示例
1. Controller 层
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
/**
* 分页查询用户列表
*/
@GetMapping
public Result<PageInfo<User>> getUsers(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer minAge,
@RequestParam(required = false) Integer maxAge) {
UserQuery query = new UserQuery();
query.setName(name);
query.setMinAge(minAge);
query.setMaxAge(maxAge);
PageInfo<User> pageInfo = userService.searchUsers(query, pageNum, pageSize);
return Result.success(pageInfo);
}
}
// 统一返回结果封装
@Data
class Result<T> {
private int code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("success");
result.setData(data);
return result;
}
}
2. Service 层
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public PageInfo<User> searchUsers(UserQuery query, int pageNum, int pageSize) {
// 开启分页
PageHelper.startPage(pageNum, pageSize);
// 执行查询
List<User> userList = userMapper.selectUsersByCondition(query);
// 返回分页结果
return new PageInfo<>(userList);
}
}
3. 前端调用示例
GET /api/users?pageNum=2&pageSize=5&name=张&minAge=18
4. 返回结果示例
{
"code": 200,
"message": "success",
"data": {
"pageNum": 2,
"pageSize": 5,
"total": 23,
"pages": 5,
"list": [
{
"id": 6,
"name": "张三",
"age": 25,
"email": "zhangsan@example.com"
},
// ... 其他4条数据
],
"prePage": 1,
"nextPage": 3,
"isFirstPage": false,
"isLastPage": false,
"hasPreviousPage": true,
"hasNextPage": true
}
}
九、注意事项
-
确保 PageHelper.startPage() 后紧跟查询语句
// ✅ 正确 PageHelper.startPage(1, 10); List<User> list = userMapper.selectAll(); // ❌ 错误:中间不能有其他代码 PageHelper.startPage(1, 10); System.out.println("开始查询"); // 这行代码会导致分页失效 List<User> list = userMapper.selectAll(); -
线程安全:PageHelper 基于 ThreadLocal,确保在同一个线程内使用
-
Count查询优化:对于复杂查询,可以自定义Count查询
<select id="selectWithCustomCount" resultType="User"> SELECT * FROM users WHERE ... </select> <select id="selectWithCustomCount_COUNT" resultType="long"> SELECT COUNT(*) FROM users WHERE ... </select>
总结
PageHelper 是一个非常强大且易用的 MyBatis 分页插件,通过简单的 PageHelper.startPage() 调用,就可以实现完整的分页功能。它的主要优点在于:
- 使用简单:一行代码实现分页
- 功能丰富:支持排序、多种分页方式等
- 兼容性好:支持多种数据库
- 性能优秀:提供Count查询优化
掌握了 PageHelper 的使用,可以极大提高开发效率和代码质量。建议多动手实践,很快就能熟练掌握!

浙公网安备 33010602011771号