Mybatis Plus 分页查询数据(图解)
大家好,我是小哈。
本小节中,我们将学习如何通过 Mybatis Plus 分页查询数据库表中的数据。
什么是分页查询?
下图是小哈从京东上查询关键词 「手机」 ,展示的手机数据就是分页查询,共有 91 页:
分页查询就是把需要查询的数据集进行分批展示,比如商品表中有 1万 条手机数据,每页按固定数量展示。
为什么需要分页查询?
-
前端页面能够展示的内容有限;
-
当数据库中数据量太多,比如 100W 条,一次性全部返回,查询速度慢,而且内存也顶不住;
表结构
了解到分页查询相关概念后,我们来上手 Mybatis Plus 的分页查询功能,还是之前小节中定义好的用户测试表, 执行脚本如下:
DROP TABLE IF EXISTS user; CREATE TABLE `user` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID', `name` varchar(30) NOT NULL DEFAULT '' COMMENT '姓名', `age` int(11) NULL DEFAULT NULL COMMENT '年龄', `gender` tinyint(2) NOT NULL DEFAULT 0 COMMENT '性别,0:女 1:男', PRIMARY KEY (`id`) ) COMMENT = '用户表';
定义实体类
定义一个名为 User
实体类:
@TableName("user")
public class User {
/** * 主键 ID, @TableId 注解定义字段为表的主键,type 表示主键类型,IdType.AUTO 表示随着数据库 ID 自增 */ @TableId(type = IdType.AUTO) private Long id; /** * 姓名 */ private String name; /** * 年龄 */ private Integer age; /** * 性别 */ private Integer gender; }
不明白 Mybatis Plus 实体类注解的小伙伴,可参考前面小节 , 有详细解释。
新增测试数据
分页查询前,先通过代码插入一些测试数据,执行代码如下:
// 循环插入 100 条测试数据
for (int i = 0; i < 100; i++) { User user = new User(); user.setName("犬小哈" + i); user.setAge(i); user.setGender(1); userMapper.insert(user); }
TIP : 不清楚如何插入数据可翻阅前面 《新增数据》 小节;
添加分页插件
接着,在 MybatisPlusConfig
配置类中,添加分页插件 PaginationInnerInterceptor
:
/**
* @Author: 犬小哈
* @From: 公众号:小哈学Java, 网站:www.quanxiaoha.com
* @Date: 2022-12-15 18:29
* @Version: v1.0.0 * @Description: TODO **/ @Configuration @MapperScan("com.quanxiaoha.mybatisplusdemo.mapper") public class MybatisPlusConfig { /** * 分页插件 * @return */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } }
开始分页查询数据
Mybatis Plus 对 Mapper 层和 Service 层都将常见的增删改查操作封装好了,只需简单的继承,即可轻松搞定对数据的增删改查,本文重点讲解分页查询相关的部分。
Mapper 层
定义一个 UserMapper
, 让其继承自 BaseMapper
:
public interface UserMapper extends BaseMapper<User> { }
然后,注入 Mapper :
@Autowired
private UserMapper userMapper;
BaseMapper
提供的分页查询相关的方法如下:
解释一下每个方法的作用:
// 分页查询,page 用于设置需要查询的页数,以及每页展示数据量,wrapper 用于组装查询条件
IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper);
// 同上,区别是用 map 来接受查询的数据
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, Wrapper<T> queryWrapper);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Wrapper<T> | queryWrapper | 实体对象封装操作类(可以为 null ) |
IPage<T> | page | 分页查询条件(可以为 RowBounds.DEFAULT ) |
示例代码
接下来,小哈来演示一些示例代码以便你快速了解如何使用分页查询:
// 组装查询条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// where age = 30
queryWrapper.eq("age", 30); // 查询第 2 页数据,每页 10 条 Page<User> page = new Page<>(2, 10); page = userMapper.selectPage(page, queryWrapper); System.out.println("总记录数:" + page.getTotal()); System.out.println("总共多少页:" + page.getPages()); System.out.println("当前页码:" + page.getCurrent()); // 当前页数据 List<User> users = page.getRecords();
执行上面的代码,实际上执行了两条 SQL : 先执行 COUNT(*)
查询出记录总数,然后才是分页语句 LIMIT
:
Page 类说明
该类继承了
IPage
类,实现了 简单分页模型 ,如果你要实现自己的分页模型可以继承Page
类或者实现IPage
类
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
records | List | emptyList | 查询数据列表 |
total | Long | 0 | 查询列表总记录数 |
size | Long | 10 | 每页显示条数,默认 10 |
current | Long | 1 | 当前页 |
orders | List | emptyList | 排序字段信息,允许前端传入的时候,注意 SQL 注入问题,可以使用 SqlInjectionUtils.check(...) 检查文本 |
optimizeCountSql | boolean | true | 自动优化 COUNT SQL 如果遇到 jSqlParser 无法解析情况,设置该参数为 false |
optimizeJoinOfCountSql | boolean | true | 自动优化 COUNT SQL 是否把 join 查询部分移除 |
searchCount | boolean | true | 是否进行 count 查询,如果指向查询到列表不要查询总记录数,设置该参数为 false |
maxLimit | Long | 单页分页条数限制 | |
countId | String | xml 自定义 count 查询的 statementId |
Service 层
Mybatis Plus 同样也封装了通用的 Service 层 CRUD 操作,并且提供了更丰富的方法。接下来,我们上手看 Service 层的代码结构,如下图:
先定义 UserService
接口 ,让其继承自 IService
:
public interface UserService extends IService<User> { }
再定义实现类 UserServiceImpl
,让其继承自 ServiceImpl
, 同时实现 UserService
接口,这样就可以让 UserService
拥有了基础通用的 CRUD 功能,当然,实际开发中,业务会更加复杂,就需要向 IService
接口自定义方法并实现:
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { }
注入 UserService
:
@Autowired
private UserService userService;
Service 层封装的分页相关方法如下:
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page); // 条件分页查询 IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
示例代码
Service 层的分页方法入参和 Mapper 差不多:
// 组装查询条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// where age = 30
queryWrapper.eq("age", 30); // 查询第 2 页数据,每页 10 条 Page<User> page = new Page<>(2, 10); page = userService.page(page, queryWrapper); System.out.println("总记录数:" + page.getTotal()); System.out.println("总共多少页:" + page.getPages()); System.out.println("当前页码:" + page.getCurrent()); // 当前页数据 List<User> users = page.getRecords();