Redis--SET与ZSET

Set数据类型,存储的数据不能重复,类似于Java中的HashSet。

  • SMEMBERS
    获取指定key中所有的成员,该命令执行会有一定的风险,如果集合中有很多个数据,返回大量的数据,
    会有一定的网络和内存开销,会阻塞redis中唯一的一个线程,这个时候就需要用到SSCAN。

  • SSCAN 分批次的获取数据,每次返回当前获取到的位置,交给下一次继续扫描。
    代码实现

@Test
    public void test04() {
        Set<Object> set = new HashSet<>();
        //每次获取500个
        ScanOptions scanOptions = new ScanOptions.ScanOptionsBuilder().count(500).build();
        // 放在try中自动释放cursor
        try (Cursor<Object> cursor = redisTemplate.opsForSet().scan("set", scanOptions)) {
            while (cursor.hasNext()) {
                set.add(cursor.next());
            }
        } catch (IOException e) {
        }
        System.out.println(set.size());
    }

ZSET同样不能存储重复的数据,后续的会覆盖之前的数据,geo本质用的是zset,geo相关的可以用zset的命令,同样针对拉取所有数据提供了解决方案,
ZSET,原理和SSCAN类似。
ZSET使用案例:基于评论次数的控制

List<Object> objects = redisTemplate.executePipelined(new SessionCallback<List>() {
            @Override
            public List execute(RedisOperations operations) throws DataAccessException {
                //添加评论
                operations.opsForZSet().add(FREQ_CONTROLLER_PERFIX, UUID.randomUUID().toString().replaceAll("-", ""),
                        System.currentTimeMillis());

                //保留一个小时内的评论
                operations.opsForZSet().removeRangeByScore(FREQ_CONTROLLER_PERFIX, 0, -3600 * 1000);

                //求一个小时内的评论
                Long num = operations.opsForZSet().zCard(FREQ_CONTROLLER_PERFIX);

                //设置key的过期时间
                operations.expire(FREQ_CONTROLLER_PERFIX, 2 * 3600, TimeUnit.SECONDS);
                return null;
            }
        });
        System.out.println(JSONObject.toJSONString(objects));

参考:https://mp.weixin.qq.com/s/mvAkPXBayAzT_RWFdsOt5A

案例:延迟队列,主要用的是redis的ZRANGEBYSCORE,根据score来回去过期的任务。
添加任务线程
在这里插入图片描述

//添加任务
        SCHEDULED_EXECUTOR_SERVICE.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try{
                    int startId=ATOMIC_INTEGER.get();
                    redisTemplate.executePipelined(new SessionCallback<List>() {
                        @Override
                        public List<String> execute(RedisOperations operations) throws DataAccessException {
                            for (int i = 0; i < 1000; i++) {
                                Task task = new Task();
                                task.setId(ATOMIC_INTEGER.incrementAndGet());
                                long delayTime = System.currentTimeMillis()+getRandomNum(0, 100)*1000;
                                task.setDelayTime(delayTime);
                                operations.opsForZSet().add(DELAY_TASK, task, delayTime);
                            }
                            return null;
                        }
                    });
                    LOGGER.info("添加任务id:{}-{}完成",startId,ATOMIC_INTEGER.get());
                }catch (Exception e){
                    e.printStackTrace();
                    LOGGER.error(e.getMessage());
                }
            }
        },0,4, TimeUnit.SECONDS);

消费线程

//消费任务
        for (int i=0;i<4;i++){
            SCHEDULED_EXECUTOR_SERVICE.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    try {
                        //获取需要执行的任务
                        String identify = redisService.acquireLockWithTimeout(DELAY_TAKS_LOCK, 10000, 1000);

                        Set<Task> setTask = (Set) redisTemplate.opsForZSet().
								reverseRangeByScore(DELAY_TASK, System.currentTimeMillis(), Double.MAX_VALUE, 0, COUNT_NUM);
                        LOGGER.info("获取到需要执行的任务数:{}",setTask.size());

                        //移除
                        LOGGER.info("移除个数{}",setTask.size());
                        List<Object> objects = redisTemplate.executePipelined(new SessionCallback<List>() {
                            @Override
                            public List execute(RedisOperations operations) throws DataAccessException {
                                for (Task t : setTask) {
                                    operations.opsForZSet().remove(DELAY_TASK, t);
                                }
                                return null;
                            }
                        });
                        LOGGER.info("删除完毕,删除的个数为{}",objects.stream().count());
                        //释放锁
                        redisService.releaseLock(DELAY_TAKS_LOCK,identify);

                        //执行任务
                        Thread.sleep(10000);
                    }catch (Exception e){
                        e.printStackTrace();
                        LOGGER.error(e.getMessage());
                    }
                }
            },0,4, TimeUnit.SECONDS);
        }

监听队列中的任务数

SCHEDULED_EXECUTOR_SERVICE.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try{
                    Long count = redisTemplate.opsForZSet().count(DELAY_TASK, 0, System.currentTimeMillis());
                    LOGGER.info("队列中总共有{}个任务",count);
                }catch (Exception e){
                    e.printStackTrace();
                    LOGGER.error(e.getMessage());
                }
            }
        },0,4, TimeUnit.SECONDS);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值