Redis实现分页查询

 在我们开发项目的过程中,经常会对数据做分页展示,如果每次请求都去查询数据库,当访问量增大时,势必会加重数据库的负载,降低数据库性能。然而,有些数据的是极少变动的,或者说变动的频率不是很高,这时如果将这些数据进行缓存,不仅可以提高程序性能,还能降低数据库的负载。下面就给出高并发下的分页数据缓存方案。

一、需要了解的一些知识点

1、redis的hmset(key, value)方法,将key值设置为value,value是map类型的数据结构

2、redis的hgetAll(key)方法,获取key的值,改值的类型为map类型的

3、关键字synchronized

4、key值包含的一些关键信息,前缀+当前的页数+每页数据的大小等

二、代码实现

          

 
  1. /* (non-Javadoc)

  2. * 默认为60秒刷新一次;采用加锁模式应对高并发

  3. */

  4. @Override

  5. public Page<StrategySummary> getAdvisorStrategys(AdvisorCondition condition) throws IOException{

  6. Pageable pageable=condition.getPage();

  7. int currentPage = pageable.getPageNumber();

  8. int pageSize = pageable.getPageSize();

  9. Map<String,String> result=RedisUtil.getMap("advisor:"+condition.getId()+"_number:"+currentPage+"_size:"+pageSize, MARKET);

  10. if (result!=null&&result.size()>0) {

  11. List<StrategySummary> dataList=JsonUtils.toJavaBeanList(result.get("data"), new TypeReference<List<StrategySummary>>() {});

  12. long total=Long.valueOf(result.get("total"));

  13. return new PageImplBean<StrategySummary>(dataList, pageable, total);

  14. } else {

  15. Page<StrategySummary> page=null;

  16. synchronized (MobileAppServiceImpl.class) { //当首个线程将数据缓存后,后面的线程需再次检查,防止重复查询数据库和缓存数据

  17. int count = 0;

  18. for (int i = 0; i < 3; i++) { //取3次,防止获取失败

  19. Map<String,String> map =RedisUtil.getMap("advisor:"+condition.getId()+"_number:"+currentPage+"_size:"+pageSize, MARKET);

  20. if (map==null||map.size()==0) {

  21. continue;

  22. }

  23. if (map!=null&&map.size()>0) {

  24. count++;

  25. break;

  26. }

  27. }

  28. if (count==0) {

  29. page= mobileAppDao.getAdvisorStrategys(condition);

  30. List<StrategySummary> dataList=page.getContent();

  31. long total=page.getTotalElements();

  32. if(dataList.size()>0){

  33. Map<String, String> map=new HashMap<String,String>();

  34. map.put("data", JsonUtils.toJsonString(dataList));

  35. map.put("total", String.valueOf(total));

  36. RedisUtil.setMapWithExpire("advisor:"+condition.getId()+"_number:"+currentPage+"_size:"+pageSize, map, MARKET);

  37. }

  38. }else{

  39. Map<String,String> map =RedisUtil.getMap("advisor:"+condition.getId()+"_number:"+currentPage+"_size:"+pageSize, MARKET);

  40. List<StrategySummary> dataList=JsonUtils.toJavaBeanList(map.get("data"), new TypeReference<List<StrategySummary>>() {});

  41. long total=Long.valueOf(map.get("total"));

  42. page= new PageImplBean<StrategySummary>(dataList, pageable, total);

  43. }

  44. }

  45. return page;

  46. }

  47.  
  48. }

 

          

### 使用 Redis 实现带条件的分页查询 为了实现带有条件的分页查询,在 Redis 中可以采用多种方法来存储和检索数据。一种常见的做法是利用有序集合 (Sorted Set) 来保存记录及其分数,从而能够高效地执行范围查询。 #### 方法一:使用 Sorted Set 和 ZRANGEBYSCORE 命令 通过给每条记录分配一个唯一的分数并将其存入 Sorted Set,ZRANGEBYSCORE 可用于获取满足特定分数区间内的成员列表。这允许基于某些数值型字段(如时间戳、评分等)进行有条件筛选后再做分页处理[^1]。 ```python import redis r = redis.Redis() def add_item(key, item_id, score): r.zadd(key, {item_id: score}) def get_paginated_items(key, min_score, max_score, offset=0, limit=10): items = r.zrangebyscore( key, min=min_score, max=max_score, start=offset, num=limit, withscores=True ) return items ``` 此方式适用于当过滤依据为连续值域的情况;对于离散属性,则需考虑其他策略。 #### 方法二:组合 Hashes 与 Sets 或 Lists 如果要根据多个非数值类型的条件来进行分页查询,比如标签分类或是状态标记,那么可以在每次新增/更新实体时同步维护对应的索引结构——即针对每一个可能作为查询维度的信息创建独立 set/list,并保持其内部元素指向实际 hash 记录的位置关系。之后借助 SINTER 等交集运算指令找出符合条件项再实施 LIMIT OFFSET 的切片操作完成最终结果返回[^2]。 ```python def index_by_field(item_key, field_value, member): r.sadd(f"{field_value}", member) def unindex_by_field(field_value, member): r.srem(f"{field_value}", member) def find_with_conditions(fields_values, page_size=10, cursor=0): keys_pattern = " ".join([f"{fv}" for fv in fields_values]) res = r.execute_command('SUNIONSTORE', 'temp_set', *fields_values) while True: next_cursor, members = r.scan(cursor, match='*', count=page_size) yield from members if next_cursor == 0: break cursor = next_cursor r.delete('temp_set') ``` 上述代码片段展示了如何构建多维索引来支持复杂条件下的快速查找以及分页展示功能。需要注意的是,这种方法可能会占用较多内存空间,因此应权衡性能需求与资源消耗之间的平衡点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值