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

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

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


public interface UserRepository extends MongoRepository<User, String>, QueryDslPredicateExecutor<User> {
@Query("{ 'name' : ?0 }")
List<User> findUsersByName(String name);


@Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
List<User> findUsersByAgeBetween(int ageGT, int ageLT);


List<User> findByName(String name);


List<User> findByNameLikeOrderByAgeAsc(String name);


List<User> findByAgeBetween(int ageGT, int ageLT);


@Query(value = "{}", fields = "{name : 1}")
List<User> findNameAndId();


@Query(value = "{}", fields = "{_id : 0}")
List<User> 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);最后设置结果的排序.

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

调用方法:

 // 序列号
String deviceSerial="123456";
//集合的名字,就相当于表名
String cllectionName="device";
//返回第几页
int pageIndex = 0;
//每页的大小
int pageSize = 10;
PageImpl<DeviceStatusItem> pageImpl = deviceStatusRepository
.pageDeviceStatusItemByDeviceSerial(deviceSerial, collectionName, pageIndex, pageSize);
System.out.println("list:" + pageImpl.getContent() + " number:" + pageImpl.getNumber() + " size:"
+ pageImpl.getSize() + " pages:" + pageImpl.getTotalPages()
+ " TotalElements:" + pageImpl.getTotalElements());

解析: 这个PageImpl 方法名很清晰了.

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

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

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

一共多少页: pageImpl.getTotalPages()

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

优化的分页实现

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

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

    /**
* deviceSerials分页查询,不使用count,不然每次都要全表扫描.
*/
public PageImpl<DeviceStatusItem> pageDeviceStatusItemByDeviceSerialListNotCount(List<String> 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<DeviceStatusItem> items = readMongoTemplate.find(query, DeviceStatusItem.class, collectionName);
// System.out.println("stories:" + stories.size() + " count:" + count);
return (PageImpl<DeviceStatusItem>) PageableExecutionUtils.getPage(items, pageable, () -> 0);
}

把count去掉就好.

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

使用count和不使用count性能比较

1.准备数据:

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

2.测试程序

只列了主要的程序:

    public static void readUseCount(IDeviceShadowQueryService deviceShadowQueryService, List<String> deviceSerials) {
int pageIndex = 0;
int pageSize = 80;
int totalPages = 0;
Pagination<DeviceStatusDto> 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

转载请注明出处: http://www.cnblogs.com/jycboy/p/8969035.html

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

  1. MongoDB学习-->Spring Data Mongodb框架之Repository

    application-dev.yml server: port: 8888 mongo: host: localhost port: 27017 timeout: 60000 db: mamabik ...

  2. mongodb Decimal Spring data mongodb Decimal128 SpringMvc 序列化字符串 json converter

    Mongodb 3.4 就开始支持Decimal 类型,解决double的精度问题,但是不太好用,MapReduce的时候Array.sum 也不能计算 Decimal.比较坑,但是聚合可以用 Spr ...

  3. Spring Data MongoDB example with Spring MVC 3.2

    Spring Data MongoDB example with Spring MVC 3.2 Here is another example web application built with S ...

  4. 使用Spring访问Mongodb的方法大全——Spring Data MongoDB查询指南

    1.概述 Spring Data MongoDB 是Spring框架访问mongodb的神器,借助它可以非常方便的读写mongo库.本文介绍使用Spring Data MongoDB来访问mongod ...

  5. Spring data mongodb 聚合,投射,内嵌数组文档分页.

    尽量别直接用 DBObject  ,Spring data mongodb 的api 本来就没什么多大用处,如果还直接用 DBObject 那么还需要自己去解析结果,说动做个对象映射,累不累 Spri ...

  6. JAVA 处理 Spring data mongodb 时区问题

    Spring data mongodb 查询出结果的时候会自动 + 8小时,所以我们看起来结果是对的 但是我们查询的时候,并不会自动 + 8小时,需要自己处理 解决方法 1   @JsonFormat ...

  7. Spring Data MongoDB 三:基本文档查询(Query、BasicQuery)(一)

    一.简单介绍 Spring Data  MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate对MongoDB的CRUD的操作,上一 ...

  8. Introduction to Spring Data MongoDB

    Introduction to Spring Data MongoDB I just announced the new Spring 5 modules in REST With Spring: & ...

  9. Spring Data MongoDB 一:入门篇(环境搭建、简单的CRUD操作)

    一.简介 Spring Data  MongoDB 项目提供与MongoDB文档数据库的集成.Spring Data MongoDB POJO的关键功能区域为中心的模型与MongoDB的DBColle ...

  10. Spring Data MongoDB 分页查询

    在上篇文章 Spring Data MongoDB 环境搭建 基础上进行分页查询 定义公用分页参数类,实现 Pageable 接口 import java.io.Serializable; impor ...

随机推荐

  1. hdu 3499 flight 【分层图】+【Dijkstra】

    <题目链接> 题目大意: 现在给你一些点,这些点之间存在一些有向边,每条边都有对应的边权,有一次机会能够使某条边的边权变为原来的1/2,求从起点到终点的最短距离. 解题分析: 分层图最短路 ...

  2. 004.Heartbeat+HAProxy+MySQL半复制高可用架构

    一 基础环境 节点 系统版本 MySQL版本 业务IP 心跳IP Master CentOS 7.5 MySQL 5.6 192.168.88.100 192.168.77.100 Slave Cen ...

  3. Java内存管理-你真的理解Java中的数据类型吗(十)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 作为Java程序员,Java 的数据类型这个是一定要知道的! 但是不管是那种数据类型最 ...

  4. MongoDB+php7搭建

    0x00前言: 今天一位非计算机专业的朋友问我怎么打开.bson文件,我第一反应.bson文件是什么,网上查了下是mongodb的传输文件.也就是类似于mysql的.sql文件一样 之前看过mongo ...

  5. XML相关的安全漏洞-XXE,XPATH小结

    0x00前言: 本文主要小结以下php下的xpath查询xml结构的漏洞利用和XXE漏洞利用 xml是可扩展标记语言,它被设计出来是为了存储传输数据的. 它的结构是树形结构,并且标签要成对出现比如下面 ...

  6. python与mysql交互中的各种坑

    开始学python 交互MySQLdb,踩了很多坑 第一个 %d format: a number is required, not str 参照以下博客: https://blog.csdn.net ...

  7. QtQuick大坑笔记之Http的Get与Post操作(带cookie)

    前言 最近在为单位做一个简单的手机App,基于Qt技术栈的选择了QtQuick来开发.不得不说QtQucik开发的确舒服,很多东西都不用写就可以只用,UI定义起来也比较自由.但是本人想通过cookie ...

  8. NineveGL引擎学习笔记

  9. js实现一个一个打印字体的功能

    var str = "ddll台湾八百壮士抗议苹果正式发邀请函西安铁警查倒票案自制航模逼停高铁林志玲遭老总熊抱拖拽游艇事故通报大马外交官被暗杀鹿晗又和邮筒合影奥迪男辱骂环卫工 " ...

  10. 2017.08.06【NOIP提高组】模拟赛B组

    Summary 今天的比赛60+100+100=260分,没有想到第一题正解是搜索,我与AK差一段距离,这段距离,叫倒着搜.总的来说不是很难. Problem T1 天平 题目大意 给你N个排序好的砝 ...