转载于:http://www.cnblogs.com/jycboy/p/8969035.html
在用spring-data-mongodb框架开发的过程中,需要实现分页查询,就百度了下,没找到满意的又google了下,找到了思路.
在spring-data-mongodb 官方文档中,建议你使用PagingAndSortingRepository 来实现分页,但是我是真的不喜欢这个设计啊!!
用方法名来映射查询语句,框架会自动生成执行代码,还为此定义了一套语法,举个例子:
复制代码
public interface UserRepository extends MongoRepository
@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 刚开始可能感觉很简单,但是一旦字段多了查询条件复杂了! 你根本不知道自己在写什么!别人看你的代码一长串方法名,也是直接懵逼的… 而 查出来的许多分页查询也是直接使用的PagingAndSortingRepository 这个接口,自动生成…非常不喜欢…就去查怎么使用MongoTemplate实现… 先下班…放假回来补上…哈哈 庆祝五一上班,把没写的写完… 使用MongoTemplate实现分页 } MongoOperations 是MongoTemplate的接口,它的具体实现就是MongoTemplate,所以这里使用MongoTemplate或MongoOperations 都可以. // page:第几页, size:每页的大小 调用方法: 查询的结果集: pageImpl.getContent(), 当前页是第几个: pageImpl.getNumber() 当前页的大小: pageImpl.getSize() 一共多少页: pageImpl.getTotalPages() 一共多少条记录: pageImpl.getTotalElements() 优化的分页实现 你优化的实现就是去掉count,就想下边这样: 复制代码 这样去掉count后, 只有在最后一次查询时才会进行全表扫描. 使用count和不使用count性能比较 准备了50万数据,不是很多,就简单测试下, 数据量越大效果越明显. 2.测试程序 只列了主要的程序: 复制代码 复制代码 使用count,开始读取, 大小:99975 不使用count,读取完毕,大小:99975 花费时间:109696 不使用count,节约时间: 112792-109696=2900= 2.9s 参考: https://stackoverflow.com/questions/27296533/spring-custom-query-with-pageable?rq=1
复制代码
@Repository(“deviceStatusRepository”)
public class DeviceStatusRepository {@Autowired
private MongoOperations mongoOperations;
/**
* 分页查询
*/
public PageImpl
复制代码
解析:
public PageRequest(int page, int size) {
this(page, size, null);
}
2. 构建Query 查询条件.我这里先是指定了根据序列号查询,然后设置分页请求 query.with(pageable);最后设置结果的排序.
复制代码
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 方法名很清晰了.
使用上边的分页实现没有大的问题, 但是有一个性能问题, 当你的集合很大的时候, 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去掉就好.
1.准备数据:
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
3.测试结果
使用count,读取完毕,大小:99975 花费时间:112792