Mongodb系列- spring-data-mongodb使用MongoTemplate实现分页查询

2023-11-06

转载于:http://www.cnblogs.com/jycboy/p/8969035.html

在用spring-data-mongodb框架开发的过程中,需要实现分页查询,就百度了下,没找到满意的又google了下,找到了思路.

在spring-data-mongodb 官方文档中,建议你使用PagingAndSortingRepository 来实现分页,但是我是真的不喜欢这个设计啊!!

用方法名来映射查询语句,框架会自动生成执行代码,还为此定义了一套语法,举个例子:

复制代码
public interface UserRepository extends MongoRepository<User, String>, QueryDslPredicateExecutor {
@Query("{ ‘name’ : ?0 }")
List findUsersByName(String name);

@Query("{ ‘age’ : { $gt: ?0, $lt: ?1 } }")
List findUsersByAgeBetween(int ageGT, int ageLT);

List findByName(String name);

List findByNameLikeOrderByAgeAsc(String name);

List findByAgeBetween(int ageGT, int ageLT);

@Query(value = “{}”, fields = “{name : 1}”)
List findNameAndId();

@Query(value = “{}”, fields = “{_id : 0}”)
List findNameAndAgeExcludeId();
}

复制代码
这个接口类只定义了接口,并不需要实现,因为SDM框架(spring-data-mongodb简称,以下都使用简称)会帮你生成代码…

findByAgeBetween(int ageGT, int ageLT);-> 就是where ageGT <age and age <ageLT;

刚开始可能感觉很简单,但是一旦字段多了查询条件复杂了! 你根本不知道自己在写什么!别人看你的代码一长串方法名,也是直接懵逼的…

而 查出来的许多分页查询也是直接使用的PagingAndSortingRepository 这个接口,自动生成…非常不喜欢…就去查怎么使用MongoTemplate实现…

先下班…放假回来补上…哈哈

庆祝五一上班,把没写的写完…

使用MongoTemplate实现分页
复制代码
@Repository(“deviceStatusRepository”)
public class DeviceStatusRepository {

@Autowired
private MongoOperations mongoOperations;


/**
 * 分页查询
 */
public PageImpl<DeviceStatusItem> pageDeviceStatusItemByDeviceSerial(String deviceSerial, String collectionName,
        int pageIndex, int pageSize) {
    Query query = Query.query(
            Criteria.where(CONSTS.DEVICE_SERIAL_FIELD).is(deviceSerial));
    // 每页五个
    Pageable pageable = new PageRequest(pageIndex, pageSize); // get 5 profiles on a page
    query.with(pageable);
    // 排序
    query.with(new Sort(Direction.ASC, CONSTS.DEVICE_SERIAL_FIELD, CONSTS.DOMAINID_FIELD));
    // 查询总数
    int count = (int) mongoOperations.count(query, DeviceStatusItem.class, collectionName);
    List<DeviceStatusItem> items = mongoOperations.find(query, DeviceStatusItem.class, collectionName);
    // System.out.println("stories:" + stories.size() + " count:" + count);
    return (PageImpl<DeviceStatusItem>) PageableExecutionUtils.getPage(items, pageable, () -> count);
}

}
复制代码
解析:

MongoOperations 是MongoTemplate的接口,它的具体实现就是MongoTemplate,所以这里使用MongoTemplate或MongoOperations 都可以.

  1. 创建PageRequest 对象,这是SDM框架提供的现成的分页请求类.构造函数很简单:

// page:第几页, size:每页的大小
public PageRequest(int page, int size) {
this(page, size, null);
}
2. 构建Query 查询条件.我这里先是指定了根据序列号查询,然后设置分页请求 query.with(pageable);最后设置结果的排序.

  1. 使用SDM框架自带的工具类PageableExecutionUtils 返回PageImpl .这里的PageableExecutionUtils 和PageImpl 其实都可以自己实现,你可以打开PageImpl 看一下代码很简单,就是对查询结果封装了下,方便数据的返回.

调用方法:
复制代码
1 // 序列号
2 String deviceSerial=“123456”;
3 //集合的名字,就相当于表名
4 String cllectionName=“device”;
5 //返回第几页
6 int pageIndex = 0;
7 //每页的大小
8 int pageSize = 10;
9 PageImpl pageImpl = deviceStatusRepository
10 .pageDeviceStatusItemByDeviceSerial(deviceSerial, collectionName, pageIndex, pageSize);
11 System.out.println(“list:” + pageImpl.getContent() + " number:" + pageImpl.getNumber() + " size:"
12 + pageImpl.getSize() + " pages:" + pageImpl.getTotalPages()
13 + " TotalElements:" + pageImpl.getTotalElements());
复制代码
解析: 这个PageImpl 方法名很清晰了.

查询的结果集: pageImpl.getContent(),

当前页是第几个: pageImpl.getNumber()

当前页的大小: pageImpl.getSize()

一共多少页: pageImpl.getTotalPages()

一共多少条记录: pageImpl.getTotalElements()

优化的分页实现
使用上边的分页实现没有大的问题, 但是有一个性能问题, 当你的集合很大的时候, count每次执行都会全表扫描一下,因为你只有全表扫描才知道有多少数量,耗费很多时间.而这个时间是没有必要的.

你优化的实现就是去掉count,就想下边这样:

复制代码
/**
* deviceSerials分页查询,不使用count,不然每次都要全表扫描.
*/
public PageImpl pageDeviceStatusItemByDeviceSerialListNotCount(List deviceSerials,
String collectionName, int pageIndex, int pageSize) {
Query query = Query.query(Criteria.where(CONSTS.DEVICE_SERIAL_FIELD).in(deviceSerials));
// 每页五个
Pageable pageable = new PageRequest(pageIndex, pageSize); // get 5 profiles on a page
query.with(pageable);
// 排序
query.with(new Sort(Direction.ASC, CONSTS.DEVICE_SERIAL_FIELD, CONSTS.DOMAINID_FIELD));
List items = readMongoTemplate.find(query, DeviceStatusItem.class, collectionName);
// System.out.println(“stories:” + stories.size() + " count:" + count);
return (PageImpl) PageableExecutionUtils.getPage(items, pageable, () -> 0);
}
复制代码
把count去掉就好.

这样去掉count后, 只有在最后一次查询时才会进行全表扫描.

使用count和不使用count性能比较
1.准备数据:

准备了50万数据,不是很多,就简单测试下, 数据量越大效果越明显.

2.测试程序

只列了主要的程序:

复制代码
public static void readUseCount(IDeviceShadowQueryService deviceShadowQueryService, List deviceSerials) {
int pageIndex = 0;
int pageSize = 80;
int totalPages = 0;
Pagination pagination = deviceShadowQueryService
.readDeviceStatusDtoByDeviceSerials(deviceSerials, pageIndex, pageSize);
int size = pagination.getRecords().size();
totalPages = pagination.getTotalPages();
// 第1页开始
for (int i = 1; i < totalPages; i++) {
pagination = deviceShadowQueryService.readDeviceStatusDtoByDeviceSerials(deviceSerials, i, pageSize);
totalPages = pagination.getTotalPages();
size = pagination.getRecords().size();
}
count++;
if (count % 100 == 0)
System.out.println(“totalPages:” + totalPages + " size:" + size);
}

public static void readNoCount(IDeviceShadowQueryService deviceShadowQueryService, List<String> deviceSerials) {
    int pageIndex = 0;
    int pageSize = 80;
    Pagination<DeviceStatusDto> page = deviceShadowQueryService
            .readDeviceStatusDtoByDeviceSerialsList(deviceSerials, pageIndex, pageSize);
    int size = page.getRecords().size();
    while (size == pageSize) {
        pageIndex++;
        page = deviceShadowQueryService.readDeviceStatusDtoByDeviceSerialsList(deviceSerials, pageIndex, pageSize);
        size = page.getRecords().size();
    }
    count++;
    if (count % 100 == 0)
        System.out.println("pageIndex:" + pageIndex + " size:" + size);
}

复制代码
3.测试结果

使用count,开始读取, 大小:99975
使用count,读取完毕,大小:99975 花费时间:112792

不使用count,读取完毕,大小:99975 花费时间:109696

不使用count,节约时间: 112792-109696=2900= 2.9s

参考:

https://stackoverflow.com/questions/27296533/spring-custom-query-with-pageable?rq=1

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mongodb系列- spring-data-mongodb使用MongoTemplate实现分页查询 的相关文章

随机推荐

  • Java中的异常处理机制的简单原理和应用。

    异常是指java程序运行时 非编译 所发生的非正常情况或错误 与现实生活中的事件很相似 现实生活中的事件可以包含事件发生的时间 地点 人物 情节等信息 可以用一个对象来表示 Java使用面向对象的方式来处理异常 它把程序中发生的每个异常也都
  • 基于STM32F103单片机的车牌识别图像处理识别系统 原理图PCB程序设计

    硬件电路的设计 末尾附文件 系统硬件系统分析设计 1 STM32单片机核心电路设计 STM32系列处理器是意法半导体ST公司生产的一种基于ARM 7架构的32位 支持实时仿真和跟踪的微控制器 选择此款控制芯片是因为本系统设计并非追求成本的最
  • React通过axios拿到数据后,使用hooks,通过map函数对列表进行渲染

    导入hooks 导入你封装的http模块 引入样式 import React useEffect useState from react import http from API import index scss 默认导出一个函数组价 并
  • C#学习记录——.NET的三层架构

    每一个不曾起舞的日子 都是对生命的辜负 尼采 每一个不读书的的日子 都是对时光的辜负 今天学习 零基础学C 3 0 NET的三层架构 为了实现大型应用系统后续功能的扩展性和程序的灵活性 NET编程语言借鉴了JAVA的MVC思想 产生了三层架
  • MySQL - 第9节 - MySQL内外连接

    目录 1 内连接 2 外连接 2 1 左外连接 2 2 右外连接 3 简单案例 1 内连接 表的连接分为内连接和外连接 内连接实际上就是利用where 子句对两种表形成的笛卡儿积进行筛选 我们前面学习的查询都是内连接 也是在开发过程中使用的
  • Markdown语法--Obsidian笔记

    Markdown 语法 笔记 文章目录 Markdown 语法 笔记 语法分类 文字层级类 1 标题 2 段落 3 区块引用 4 代码区块 5 列表 6 待办事项 文字格式类 1 样式 2 表格 链接引用类 1 链接 2 图片 3 脚注 4
  • Dubbo与Spring Cloud的区别

    这是个老生常谈的问题 每个技术团队在业务转型微服务化架构的时候都会纠结过这个选型问题 首先 dubbo 之前确实在 2012 年的时候发布了最后一个版本 2 5 3 并且停止维护更新 在2017年的时候又 起死回生 官方宣布重启更新 并重点
  • 2021图像检索综述

    论文地址 Deep Image Retrieval A Survey 本文是2021年最新的关于图像检索的综述 介绍了基于内容的图像检索 content based image retrieval CBIR 在深度学习技术上的进展 目录 0
  • Traceback (most recent call last): File “D:/python_workspace/hello.py“, line 3, in <module>

    错误背景 python的初学者 在学习多行语句 错误信息如下 错误原因 变量有字符串类型 有整型类型 有浮点型 在java 里面 String标识字符串类型 Int标识整型 在python里面 a yy1 就是字符串类型 a 1就是数字类型
  • 29_content 阶段的concat 模块

    文章目录 提升性能 content 阶段的 caoncat 模块 concat 模块的指令 示例配置 提升性能 content 阶段的 caoncat 模块 功能 当页面需要访问多个小文件时 把它们内容合并到一次http 响应中返回 提升性
  • 数组排序的方法?

    1 sort排序 let arr 1 2 3 4 5 6 7 8 9 0 9 8 7 6 3 4 5 5 var res console log arr 排序前 1 2 3 4 5 6 7 8 9 0 9 8 7 6 3 4 5 5 arr
  • SSD目标检测算法原理(上)

    目录 一 目标检测概述 1 1 项目演示介绍 1 2 图片识别背景 1 3 目标检测定义 二 目标检测算法原理 2 1 任务描述 2 2 目标检测算法必备基础 2 3目标检测算法模型输出 目标检测 overfeat模型 R CNN模型 候选
  • h2database源码解析-查询优化器原理

    目录 一 成本计算规则 二 单表查询 三 多表关联查询 一 成本计算规则 h2的查询优化器基于成本的 因此在执行查询前 会基于成本计算使用哪个索引 如果涉及多表关联 还会计算不同表关联顺序的成本 最终基于最小成本得出执行计划 单表查询时 遍
  • 树莓派驱动开发简单案例完整过程(动态加载驱动)

    1 下载树莓派os镜像 https www raspberrypi org downloads raspbian 2 使用命令 uname a 查看树莓派内核 Linux raspberrypi 4 19 118 v7 1311 SMP M
  • JQuery筛选器

    jQuery提供了强大的选择器让我们获取对象 在这边 我人为地将jQuery选择器分为两大部分 选择对象和筛选条件 选择对象表示要获取什么对象 筛选条件是对获取的对象进行筛选 最终留下符合某些特征的对象 1 选择对象1 基本 id根据给定的
  • VC++、MFC中最好的开源项目

    介绍一下用VC MFC写的最好的开源项目 Sourceforge net中有许多高质量的VC 开源项目 我列举了一些可以作为VC 程序员的参考 一 优秀的开源项目 7 Zip http sourceforge net projects se
  • react项目路由组件懒加载方法对比,@loadable/component和react-loadable和suspense lazy

    1 使用 loadable component方法 推荐使用这个 npm install loadable component S 先安装一下 2 在app js中引入 loadable component import Loadable
  • 随机森林回归模型--评分预测

    PS 介绍代码仅供介绍 源代码后期经过修改与介绍代码不一定完全相同 索引表 使用到的库 数据加载和预处理 划分训练集和测试集 模型选择和训练 模型评估 模型优化 结果展示 尾声 使用到的库 import pandas as pd 数据处理库
  • tomcat版本与jdk对应关系

    见tomcat官网说明 http tomcat apache org whichversion html Apache Tomcat Versions Apache Tomcat is an open source software imp
  • Mongodb系列- spring-data-mongodb使用MongoTemplate实现分页查询

    转载于 http www cnblogs com jycboy p 8969035 html 在用spring data mongodb框架开发的过程中 需要实现分页查询 就百度了下 没找到满意的又google了下 找到了思路 在sprin