微服务分页查询:MyBatis-Plus vs 自定义实现
在之前的单体项目中也好,微服务项目中也罢,对于分页查询我一直比较模糊,这次在第二个项目中再一次用到了分页查询,我就简单总结一下两个微服务项目中的分页查询的差异和共同。
项目背景:
在原先的慧径学习系统(微服务项目)中,有这样的一个用户服务:
@Override
public Page<UserDetail> queryUserDetailByPage(UserPageQuery query, UserType type) {// 1.分页条件Page<UserDetail> p = query.toMpPageDefaultSortByCreateTimeDesc();// 2.搜索条件Integer status = query.getStatus();String name = query.getName();String phone = query.getPhone();QueryWrapper<UserDetail> wrapper = new QueryWrapper<>();wrapper.eq(type != null , "u.type", type).eq(status != null, "u.status", status).eq(StringUtils.isNotBlank(phone),"u.cell_phone", phone).like(StringUtils.isNotBlank(name), "ud.name", name);// 3.查询p = getBaseMapper().queryByPage(p, wrapper);// 4.返回return p;
}
@Data
@ApiModel(description = "分页请求参数")
@Accessors(chain = true)
public class PageQuery {public static final Integer DEFAULT_PAGE_SIZE = 20;public static final Integer DEFAULT_PAGE_NUM = 1;@ApiModelProperty(value = "页码", example = "1")@Min(value = 1, message = "页码不能小于1")private Integer pageNo = DEFAULT_PAGE_NUM;@ApiModelProperty(value = "每页大小", example = "5")@Min(value = 1, message = "每页查询数量不能小于1")private Integer pageSize = DEFAULT_PAGE_SIZE;@ApiModelProperty(value = "是否升序", example = "true")private Boolean isAsc = true;@ApiModelProperty(value = "排序字段", example = "id")private String sortBy;// ...
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "分页结果")
public class PageDTO<T> {@ApiModelProperty("总条数")protected Long total;@ApiModelProperty("总页码数")protected Long pages;@ApiModelProperty("当前页数据")protected List<T> list;// 提供了多种静态方法来创建PageDTO对象public static <T> PageDTO<T> of(Page<T> page) { ... }public static <T,R> PageDTO<T> of(Page<R> page, Function<R, T> mapper) { ... }public static <T, R> PageDTO<T> of(Page<R> page, Class<T> clazz) { ... }// ...
}
在这里的分页查询实现服务中可以发现:
1.首先从参数中分离得到分页条件(页码,每页大小等)
2.其次从参数中分离得到对数据的搜索条件(用户状态,名字等)
3.调用queryByPage()方法进行分页查询,参数类型为Page<T>和QueryWrapper
而在目前的云图库项目中,用户服务中的分页查询是这样实现的:
@PostMapping("/list/page/vo")@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)public BaseResponse<Page<UserVO>> listUserVOByPage(@RequestBody UserQueryRequest userQueryRequest) {ThrowUtils.throwIf(userQueryRequest == null, ErrorCode.PARAMS_ERROR);long current = userQueryRequest.getCurrent();long pageSize = userQueryRequest.getPageSize();//userService.page(分页对象,查询条件包装器)Page<User> userPage = userService.page(new Page<>(current, pageSize), userService.getQueryWrapper(userQueryRequest));// 转换为VO列表Page<UserVO> userVOPage = new Page<>(current, pageSize, userPage.getTotal());List<UserVO> userVOList = userService.getUserVOList(userPage.getRecords());userVOPage.setRecords(userVOList);return ResultUtils.success(userVOPage);}
在这里的分页查询实现服务中可以发现:
1.首先从参数中分离得到分页条件(页码,每页大小等)
2.其次从参数中分离得到对数据的搜索条件(用户状态,名字等)
3.调用userService()方法进行分页查询,参数类型为Page<T>和QueryWrapper
差异:
1. 实现方式不同
云图库项目使用 MyBatis-Plus 提供的 IService 接口中的 page() 方法实现的分页查询。它直接在 Service 层调用,使用了 MyBatis-Plus 的自动分页功能。
getBaseMapper().queryByPage() 方法: 这是一种自定义的分页查询方式,需要在 Mapper 接口中定义 queryByPage 方法,并在对应的 XML 文件中编写 SQL 语句来实现分页查询。
2. 灵活性不同
代码中的分页查询方法:
①使用 MyBatis-Plus 内置分页,自动在原始查询 SQL 基础上添加分页逻辑
②通过 QueryWrapper 构造查询条件,使用链式调用,代码简洁
③不需要编写额外的 SQL 语句
getBaseMapper().queryByPage() 方法:
①需要手动编写 SQL 语句,可以实现更复杂的分页逻辑
②可以针对特殊需求定制分页查询
③更加灵活,但需要更多的代码量
3. 性能和效率
①MyBatis-Plus 会对查询进行优化,自动处理分页逻辑
②对于简单的分页查询,性能表现良好
③在数据量特别大时,可能不如手写 SQL 精确控制
getBaseMapper().queryByPage() 方法:
①可以通过手写 SQL 优化查询性能
②可以使用数据库特有的分页语法(如 MySQL 的 LIMIT,Oracle 的 ROWNUM)
③在复杂查询场景下可能有更好的性能表现
总结
云图库项目中使用的是 MyBatis-Plus 提供的分页查询方式,这种方式简单易用,适合大多数场景。而 getBaseMapper().queryByPage() 是一种更自定义的分页方式,适合需要特殊优化或复杂查询的场景。
在实际开发中,如果项目中已经使用了 MyBatis-Plus,建议继续使用其提供的分页功能;只有在需要特殊优化或框架功能无法满足需求时,才考虑使用自定义的分页方法。