首页 > 数据库 >Redisson在日常开发过程中的使用

Redisson在日常开发过程中的使用

时间:2023-10-31 15:44:25浏览次数:29  
标签:queueId Redisson RMap get 队列 RSet 开发 日常 RScoredSortedSet

使用BitSet实现日期连续签到

  @GetMapping("/user/sign/{id}")
  public Result<String> userSign(@PathVariable("id") Long id,
                                @RequestParam(value = "date", required = false) 
                                String completeDated) throws IOException {
   
    LocalDateTime now = LocalDateTime.now();
    String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = "M2B:USER:SIGN" + ":" + id + ":" + keySuffix;
    RBitSet bitSet = redissonClient.getBitSet(key);
    bitSet.expire(50, TimeUnit.MINUTES);
    if (id == 1) {
      // 签到,获取今天是本月的第几天,bitset下标从0开始
      int dayOfMonth = now.getDayOfMonth();
      if (bitSet.get(dayOfMonth - 1)) {
        return Result.accept("您已签到,请勿重复签到");
      } else {
        bitSet.set(dayOfMonth - 1, true);
        return Result.accept("签到成功");
      }
    } else if (id == 2) {
      // 补签
      Date date = DateUtil.parseDate(completeDate);
      Instant instant = date.toInstant();
      ZoneId zoneId = ZoneId.systemDefault();
      LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
      //4.获取今天是本月的第几天
      int dayOfMonth = localDateTime.getDayOfMonth();
      //5.写入redis SETBIT key offset 1
      bitSet.set(dayOfMonth - 1, true);
    } else if (id == 3) {
      // 签到天数(标识为1的)
      long cardinality = bitSet.cardinality();
      return Result.accept("总共签到了:" + cardinality + "天");
    } else if (id == 4) {
      // 连续签到,以及签到的天数
      int dayOfMonth = now.getDayOfMonth();
      BitSet bitSet1 = bitSet.asBitSet();
      List<Integer> signList = Lists.newArrayList();
      bitSet1.stream().forEach(signList::add);
      signList.removeIf(b -> b > dayOfMonth);
      boolean continuousSign = signList.stream().anyMatch(c -> c.equals(dayOfMonth));
      if (continuousSign) {
        System.out.println("连续签到:" + getLongDay(signList) + "天");
      }
      List<DateTime> dateTimes = DateUtil.rangeToList(DateUtil.beginOfMonth(new Date()),
          DateUtil.endOfMonth(new Date()), DateField.DAY_OF_MONTH);
      System.out.println("连续签到的日期");
      for (int signIndex : signList) {
        DateTime dateTime = dateTimes.get(signIndex);
        System.out.println(dateTime.toDateStr());
      }
      System.out.println(1);
    }
    return Result.accept(null);
  }
/**
   * 获取连续签到的天数
   *
   * @param list 传入日期的集合 此处以 List<Integer>举例
   * @return
   */
  private static int getLongDay(List<Integer> list) {
    List<Integer> list2 = new ArrayList<Integer>();// 存放中断元素的位置
    List<Integer> list3 = new ArrayList<Integer>();
    //先获取连续中断的位置,放在list2中
    for (int i = 0; i < list.size(); i++) {
      if (i == list.size() - 1) {
        break;
      } else if (list.get(i + 1) - list.get(i) != 1) {
        list2.add(i);
      }
    }
    //通过判断获取连续的个数,在list3中取最大值即可。
    if (0 == list2.size()) {
      // 没有中断 返回原集合长度
      return list.size();
    } else {
      for (int i = 0; i < list2.size(); i++) {
        if (1 == list2.size()) {
          list3.add(list2.get(0) + 1);// 中断前的天数
          list3.add(list.size() - 1 - list2.get(i));// 剩余的天数
        } else {
          if (i == 0) {
            list3.add(list2.get(0) + 1);
            list3.add(list2.get(i + 1) - list2.get(i));
          } else if (i == list2.size() - 1) {
            list3.add(list.size() - 1 - list2.get(i));
          } else {
            list3.add(list2.get(i + 1) - list2.get(i));
          }
        }
      }
      return Collections.max(list3);
    }
  }

避坑
bitset占用的内存是用最大的offset来决定的,根本不会管你实际要存多少有效数据,计算公式为

● 占用内存bit = 最大offset              
● 占用内存B = 最大offset / 8     
● 占用内存KB = 最大offset / 8 / 1024
● 占用内存MB = 最大offset / 8 / 1024 / 1024
  • 比如现在我们要存用户对一篇文章的点赞数, 以及判断用户对文章有没有点赞。

  • 如果使用bitset, 那么确实一篇文章只要一个key就行了,也没有hash或set的结构复杂,比如文章id为1, 简单点key的名字就为article⭐1。

  • 那么点赞确实很简单,如果用户id=100,看下占用内存忽略不计

  • 但如果这个时候又来了一个用户点赞,用户id=2560000呢,使用方式没有变化,也完成了点赞的统计。但是占用内存呢?
    这是什么概念?记录一篇小小的文章点赞数,即使只有两个人点赞, 就占用了312.5KB,来个几百篇文章或者动态之类的,再加上其他功能也这么使用用,这要浪费吃掉多少内存。因此用bitset的时候除了考虑系统人数规模(主要是决定bitset offset值的条件),还要考虑实际会有多少人用到这个功能。即使人数达到了很大的量级,但某个功能是个很偏僻的功能,还是要少用。

总结如下

  1. 使用之前永远要作为第一要务考虑的就是offset的基数大小问题
  2. 如果uv很小,而且offset基数又很大,不要使用,offset基数很小,可以用
  3. 如果uv非常高,offset基数即使大一点,也可以使用,但这个要综合考虑去计算offset基数到底多大,uv又有没有高到离谱的程度。否则仍然还是set或者hash之类的更适用。

HyperLogLog

场景

在移动互联网的业务场景中,数据量很大,我们需要保存这样的信息:一个 key 关联了一个数据集合,同时对这个数据集合做统计。

  • 统计一个 APP 的日活、月活数;

  • 统计一个页面的每天被多少个不同账户访问量(Unique Visitor,UV));

  • 统计用户每天搜索不同词条的个数;

  • 统计注册 IP 数。

通常情况下,我们面临的用户数量以及访问量都是巨大的,比如百万、千万级别的用户数量,或者千万级别、甚至亿级别的访问信息。
你可以通过 set 集合、bitmap 这类常用工具,但有个最大的缺点是,如果数据量巨大,比如 1 亿,甚至 10 亿将耗费巨大内存消耗。

原理

Redis HyperLogLog基于一种称为HyperLogLog算法的概率性算法来估计基数。 HyperLogLog使用一个长度为m的位数组和一些hash函数来估计集合中的唯一元素数。

在 HyperLogLog 算法中,对每个元素进行哈希处理,把哈希值转换为二进制后,根据二进制串前缀中 1 的个数来给每个元素打分。例如,一个元素的哈希值为01110100011,那么前缀中1的个数是3,因此在 HyperLogLog 算法中,这个元素的分数为3。

当所有元素的分数统计完之后,取每一个分数的倒数(1 / 2^n),然后将这些倒数相加后取倒数,就得到一个基数估计值,这个值就是HyperLogLog算法的估计结果。
HyperLogLog算法通过对位数组的长度m的大小进行取舍,折衷数据结构占用的内存与估计值的精准度(即估计误差),得到了在数据占用空间与错误较小程度之间完美的平衡。
简而言之,HyperLogLog算法的核心思想是基于哈希函数和位运算,通过将哈希值转换成比特流并统计前导0的个数,从而快速估算大型数据集中唯一值的数量。通过 hyperloglog 算法我们可以在非常大的数据集中进行极速的网页浏览器去重。

算法简介

HyperLogLog 算法的基本思想来自伯努利过程。
伯努利过程就是一个抛硬币实验的过程。抛一枚正常硬币,落地可能是正面,也可能是反面,二者的概率都是 1/2 。伯努利过程就是一直抛硬币,直到落地时出现正面位置,并记录下抛掷次数k。比如说,抛一次硬币就出现正面了,此时 k 为 1; 第一次抛硬币是反面,则继续抛,直到第三次才出现正面,此时 k 为 3。
那么如何通过伯努利过程来估算抛了多少次硬币呢?还是假设 1 代表抛出正面,0 代表反面。连续出现两次 0 的序列应该为“001”,那么它出现的概率应该是三个二分之一相乘,即八分之一。那么可以估计大概抛了 8 次硬币。
HyperLogLog 原理思路是通过给定 n 个的元素集合,记录集合中数字的比特串第一个1出现位置的最大值k,也可以理解为统计二进制低位连续为零(前导零)的最大个数。通过k值可以估算集合中不重复元素的数量m,m近似等于 2^k。

延迟队列

主要处理非立即生效的业务场景,比如

  • 订单下单30分钟内,超时未支付;

  • 优惠券、活动等需要在指定时间内生效的,

  • 会议开始前10分钟消息通知

源码实现

首先创建DelayedQueueManager 用于延迟队列的创建、获取、销毁

@Slf4j
@RequiredArgsConstructor
public class DelayedQueueManager {

   private final RedissonClient redissonClient;
   private final ThreadPoolTaskExecutor threadPoolExecutor;

   private final ConcurrentHashMap<String, DelayedQueue<?>> DELAYED_QUEUE_MAP = new ConcurrentHashMap<>();

    /**
    * 创建延时对象实例
    *
    * @param queueId       队列标识
    * @param <T>           泛型类型
    * @return              延时队列实例
    */
    public <T> DelayedQueue<T> create(String queueId) {
        // 先尝试从容器中获取延迟队列
        DelayedQueue<T> delayedQueue = (DelayedQueue<T>) DELAYED_QUEUE_MAP.get(queueId);
        // 如果未获取到,则实例化一个延迟队列对象
        if (Objects.isNull(delayedQueue)) {
            delayedQueue = new DelayedQueue<>(redissonClient, queueId, threadPoolExecutor);
            DELAYED_QUEUE_MAP.putIfAbsent(queueId, delayedQueue);
        }
        return delayedQueue;
    }

        /**
        * 获取延迟队列实例
        *
        * @param queueId               队列标识id
        * @param createIfNotExists     对象不存在时是否直接创建
        * @param <T>                   元素泛型类型
        * @return                      延时队列实例
        */
        public <T> DelayedQueue<T> get(String queueId, boolean createIfNotExists) {
            // 先尝试从容器中获取延迟队列
            final DelayedQueue<T> delayedQueue = (DelayedQueue<T>) DELAYED_QUEUE_MAP.get(queueId);
            if (Objects.isNull(delayedQueue)) {
                if (createIfNotExists) {
                    return create(queueId);
                }
                throw new BizzException("找不到延时队列【{}】的实例对象!", queueId);
            }
            else {
                return delayedQueue;
            }
        }

        /**
        * 销毁指定延时队列实例
        *
        * @param queueId       延时队列id
        */
        public void destroy(String queueId) {
            // 获取延时队列实例并调用销毁方法
            Optional.ofNullable(DELAYED_QUEUE_MAP.get(queueId)).ifPresent(DelayedQueue::destroy);
        }
    }

增加延迟队列,从redisson的BlockingQueue获取DelayedQueue,并通过守护线程,获取延迟队列中的数据,执行响应的监听器

public class DelayedQueue<T> {
    /**
     * 队列id标识
     */
    private final String queueId;
    /**
     * 是否取消的标识
     */
    private final AtomicBoolean isCancelled = new AtomicBoolean(false);
    /**
     * 守护线程
     */
    private final Future<Void> daemonThread;
    // 阻塞队列
    private final RBlockingQueue<T> blockingQueue;
    // 延迟队列
    private final RDelayedQueue<T> delayedQueue;
    // 监听器列表
    private final ConcurrentHashSet<DelayedQueueListener<T>> delayedQueueListeners = new ConcurrentHashSet<>();

    /**
     * 构造器函数
     *
     * @param redissonClient            redisson客户端实例
     * @param queueId                   队列标识
     * @param threadPoolTaskExecutor    监听器通知线程池
     */
    public DelayedQueue(RedissonClient redissonClient, String queueId, ThreadPoolTaskExecutor threadPoolTaskExecutor) {
        this.blockingQueue = redissonClient.getBlockingQueue(queueId);
        this.delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
        this.queueId = queueId;
        // 添加守护线程监听阻塞队列变化,通知到每一个监听器
        this.daemonThread = CompletableFuture.runAsync(
                () -> {
                    while (!isCancelled.get()) {
                        try {
                            // 获取延时队列中的元素(会阻塞)
                            final T value = blockingQueue.take();

                            // 向每个注册监听器发送通知
                            delayedQueueListeners.forEach(
                                    // 异步通知防止阻塞
                                    listener -> CompletableFuture.runAsync(() ->  listener.invoke(value), threadPoolTaskExecutor)
                            );
                        } catch (InterruptedException e) {
                            log.error("获取阻塞队列元素异常!队列名称:{}", this.queueId, e);
                            ThreadUtil.safeSleep(GlobalConstants.Number.THOUSAND);
                        }
                    }
                }
        );
    }

    /**
     * 添加监听器
     *
     * @param delayedQueueListener      延迟队列事件监听器
     */
    public boolean addListener(DelayedQueueListener<T> delayedQueueListener) {
        // 注册监听器
        return delayedQueueListeners.add(delayedQueueListener);
    }

    /**
     * 移除监听器
     *
     * @param delayedQueueListener      延迟队列事件监听器
     */
    public boolean removeListener(DelayedQueueListener<T> delayedQueueListener) {
        return delayedQueueListeners.remove(delayedQueueListener);
    }

    /**
     * 添加元素到延时队列
     *
     * @param element       队列元素
     * @param delay         延迟时间
     * @param timeUnit      时间单位
     */
    public void offer(T element, long delay, TimeUnit timeUnit) {
        this.delayedQueue.offer(element, delay, timeUnit);
    }

    /**
     * 销毁当前队列
     */
    public void destroy() {
        // 1. 取消守护线程任务
        if (isCancelled.compareAndSet(false, true)) {
            // 2. 取消当前正在运行的任务
            daemonThread.cancel(true);
            // 3. 清空阻塞队列和延迟队列中的元素
            this.delayedQueue.destroy();
            this.blockingQueue.clear();
        }
    }
}

延迟队列触发监听器

/**
 * 延迟队列触发监听器
 *
 */
@FunctionalInterface
public interface DelayedQueueListener<T> {
    /**
     * 触发延迟队列事件
     */
    void invoke(T t);
}

延迟队列Springboot配置,配置延迟队列线程池

@Configuration
@AutoConfigureAfter(RedissonAutoConfiguration.class)
public class DelayedQueueBeanConfiguration {
    /**
     * 延时队列异步线程池
     */
    @Bean
    @ConditionalOnMissingBean(name = "delayedQueueListenerAsyncPool")
    public ThreadPoolTaskExecutor delayedQueueListenerAsyncPool() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        //核心线程数=容器cpu核心的2倍+1
        int coreNum = TWO * Runtime.getRuntime().availableProcessors() + ONE;
        threadPoolTaskExecutor.setCorePoolSize(coreNum);
        //最大线程数是核心线程数的两倍
        threadPoolTaskExecutor.setMaxPoolSize(TWO * coreNum);
        //队列长度100
        threadPoolTaskExecutor.setQueueCapacity(HUNDRED);
        //拒绝策略是直接抛异常
        threadPoolTaskExecutor.setRejectedExecutionHandler(
            new ThreadPoolExecutor.CallerRunsPolicy()
        );
        threadPoolTaskExecutor.setBeanName("delayedQueueListenerAsyncPool");
        threadPoolTaskExecutor.setThreadNamePrefix("delay-queue-notify-");
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }

    /**
     * 延时队列管理器注入
     *
     * @param redissonClient            redisson客户端实例
     * @param threadPoolTaskExecutor    线程池实例
     */
    @Bean
    @ConditionalOnBean(RedissonClient.class)
    public DelayedQueueManager delayedQueueManager(RedissonClient redissonClient, 
                  @Qualifier("delayedQueueListenerAsyncPool")  ThreadPoolTaskExecutor threadPoolTaskExecutor) {
        return new DelayedQueueManager(redissonClient, threadPoolTaskExecutor);
    }
}

方法调用,此处案例为:优化券创建后,根据配置生效的时间进行生效

String delayedQueueId = RedisKeyUtil.getCouponEffectDelayedQueueKey();
DelayedQueue<CouponVo> couponEffectDelayedQueue
    = delayedQueueManager.get(delayedQueueId, true);
couponEffectDelayedQueue.addListener(couponEffectDelayedQueueListener);
// couponVo 优惠券, between 优惠券开始的时间(延迟的时间)
couponEffectDelayedQueue.offer( couponVo , between, TimeUnit.SECONDS);

监听延迟队列生效,并执行生效方法

@Slf4j
@Component
@RequiredArgsConstructor
public class CouponEffectDelayedQueueListener implements DelayedQueueListener<CouponVo> {

    private final CouponHandler couponHandler;

    @Override
    public void invoke(CouponVo couponVo) {
        String effectTime = DateUtil.format(couponVo.getSendStartTime(), DatePattern.NORM_DATETIME_FORMAT);
        log.info("监听到优惠券编号{}生效延迟队列, 优惠券生效时间:{}",  couponVo.getCouponNo(), effectTime);
        try {
            couponHandler.changeCouponStatus(CouponDto.builder()
                .ids(Lists.newArrayList(couponVo.getId()))
                .status(SendCouponStatusEnum.IN_USING)
                .modifierId(-1L)
                .modifyTime(new Date()).build()
            );
            log.info("优惠券:{} 状态生效成功", couponVo.getCouponNo());
        } catch (Exception e) {
            log.warn("优惠券:{} 状态生效失败", couponVo.getCouponNo(), e);
        }
    }
}

Reids命令对应Redissson方法

Redis命令 Redisson对象方法
AUTH Config.setPassword()
BITCOUNT RBitSet.cardinality()
RBitSet.cardinalityAsync()
RBitSetReactive.cardinality()
BITOP RBitSet.or()
RBitSet.orAsync()
RBitSetReactive.or()
RBitSet.and()
RBitSet.andAsync()
RBitSetReactive.and()
RBitSet.not()
RBitSet.xor()
RBitSet.xorAsync()
RBitSetReactive.xor()
BITPOS RBitSet.length()
RBitSet.lengthAsync()
RBitSetReactive.length()
BLPOP RBlockingQueue.take()
RBlockingQueue.takeAsync()
RBlockingQueueReactive.take()
RBlockingQueue.poll()
RBlockingQueue.pollAsync()
RBlockingQueueReactive.poll()
RBlockingQueue.pollFromAny()
RBlockingQueue.pollFromAnyAsync()
RBlockingQueueReactive.pollFromAny()
BRPOP RBlockingDeque.takeLast()
RBlockingDeque.takeLastAsync()
RBlockingDequeReactive.takeLast()
BRPOPLPUSH RBlockingQueue.pollLastAndOfferFirstTo()
RBlockingQueue.pollLastAndOfferFirstToAsync()
RBlockingQueueReactive.pollLastAndOfferFirstTo()
CLIENT SETNAME Config.setClientName()
CLUSTER INFO ClusterNode.info()
CLUSTER KEYSLOT RKeys.getSlot()
RKeys.getSlotAsync()
RKeysReactive.getSlot()
CLUSTER NODES 在ClusterConnectionManager里使用
DBSIZE RKeys.count()
RKeys.countAsync()
RKeysReactive.count()
DECR RAtomicLong.decrementAndGet()
RAtomicLong.decrementAndGetAsync()
RAtomicLongReactive.decrementAndGetAsync()
DEL RObject.delete()
RObject.deleteAsync()
RObjectReactive.delete()
RKeys.delete()
RKeys.deleteAsync()
STRLEN RBucket.size()
RBucket.sizeAsync()
RBucketReactive.size()
EVAL RScript.eval()
RScript.evalAsync()
RScriptReactive.eval()
CLIENT REPLY RBatch.executeSkipResult()
EVALSHA RScript.evalSha()
RScript.evalShaAsync()
RScriptReactive.evalSha()
EXISTS RObject.isExists()
RObject.isExistsAsync()
RObjectReactive.isExists()
FLUSHALL RKeys.flushall()
RKeys.flushallAsync()
RKeysReactive.flushall()
FLUSHDB RKeys.flushdb()
RKeys.flushdbAsync()
RKeysReactive.flushdb()
GEOADD RGeo.add()
RGeo.addAsync()
RGeoReactive.add()
GEODIST RGeo.dist()
RGeo.distAsync()
RGeoReactive.dist()
GEOHASH RGeo.hash()
RGeo.hashAsync()
RGeoReactive.hash()
GEOPOS RGeo.pos()
RGeo.posAsync()
RGeoReactive.pos()
GEORADIUS RGeo.radius()
RGeo.radiusAsync()
RGeoReactive.radius()
RGeo.radiusWithDistance()
RGeo.radiusWithDistanceAsync()
RGeoReactive.radiusWithDistance()
RGeo.radiusWithPosition()
RGeo.radiusWithPositionAsync()
RGeoReactive.radiusWithPosition()
GEORADIUSBYMEMBER RGeo.radius()
RGeo.radiusAsync()
RGeoReactive.radius()
RGeo.radiusWithDistance()
RGeo.radiusWithDistanceAsync()
RGeoReactive.radiusWithDistance()
RGeo.radiusWithPosition()
RGeo.radiusWithPositionAsync()
RGeoReactive.radiusWithPosition()
GET RBucket.get()
RBucket.getAsync()
RBucketReactive.get()
GETBIT RBitSet.get()
RBitSet.getAsync()
RBitSetReactive.get()
GETSET RBucket.getAndSet()
RBucket.getAndSetAsync()
RBucketReactive.getAndSet()
RAtomicLong.getAndSet()
RAtomicLong.getAndSetAsync()
RAtomicLongReactive.getAndSet()
RAtomicDouble.getAndSet()
RAtomicDouble.getAndSetAsync()
RAtomicDoubleReactive.getAndSet()
HDEL RMap.fastRemove()
RMap.fastRemoveAsync()
RMapReactive.fastRemove()
HEXISTS RMap.containsKey()
RMap.containsKeyAsync()
RMapReactive.containsKey()
HGET RMap.get()
RMap.getAsync()
RMapReactive.get()
HSTRLEN RMap.valueSize()
RMap.valueSizeAsync()
RMapReactive.valueSize()
HGETALL RMap.readAllEntrySet()
RMap.readAllEntrySetAsync()
RMapReactive.readAllEntrySet()
HINCRBY RMap.addAndGet()
RMap.addAndGetAsync()
RMapReactive.addAndGet()
HINCRBYFLOAT RMap.addAndGet()
RMap.addAndGetAsync()
RMapReactive.addAndGet()
HKEYS RMap.readAllKeySet()
RMap.readAllKeySetAsync()
RMapReactive.readAllKeySet()
HLEN RMap.size()
RMap.sizeAsync()
RMapReactive.size()
HMGET RMap.getAll()
RMap.getAllAsync()
RMapReactive.getAll()
HMSET RMap.putAll()
RMap.putAllAsync()
RMapReactive.putAll()
HSET RMap.put()
RMap.putAsync()
RMapReactive.put()
HSETNX RMap.fastPutIfAbsent()
RMap.fastPutIfAbsentAsyncRMapReactive.fastPutIfAbsent()
HVALS RMap.readAllValues()
RMap.readAllValuesAsync()
RMapReactive.readAllValues()
INCR RAtomicLong.incrementAndGet()
RAtomicLong.incrementAndGetAsync()
RAtomicLongReactive.incrementAndGet()
INCRBY RAtomicLong.addAndGet()
RAtomicLong.addAndGetAsync()
RAtomicLongReactive.addAndGet()
KEYS RKeys.findKeysByPattern()
RKeys.findKeysByPatternAsync()
RKeysReactive.findKeysByPattern()
RedissonClient.findBuckets()
LINDEX RList.get()
RList.getAsync()
RListReactive.get()
LLEN RList.size()
RList.sizeAsync()
RListReactive.Size()
LPOP RQueue.poll()
RQueue.pollAsync()
RQueueReactive.poll()
LPUSH RDeque.addFirst()
RDeque.addFirstAsync()
RDequeReactive.addFirst()
RDeque.offerFirst()
RDeque.offerFirstAsync()
RDequeReactive.offerFirst()
LRANGE RList.readAll()
RList.readAllAsync()
RListReactive.readAll()
LREM RList.fastRemove()
RList.fastRemoveAsync()
RList.remove()
RList.removeAsync()
RListReactive.remove()
RDeque.removeFirstOccurrence()
RDeque.removeFirstOccurrenceAsync()
RDequeReactive.removeFirstOccurrence()
RDeque.removeLastOccurrence()
RDeque.removeLastOccurrenceAsync()
RDequeReactive.removeLastOccurrence()
LSET RList.fastSet()
RList.fastSetAsync()
RListReactive.fastSet()
LTRIM RList.trim()
RList.trimAsync()
RListReactive.trim()
LINSERT RList.addBefore()
RList.addBeforeAsync()
RList.addAfter()
RList.addAfterAsync()
RListReactive.addBefore()
RListReactive.addAfter()
MGET RedissonClient.loadBucketValues()
MIGRATE RObject.migrate()
RObject.migrateAsync()
MOVE RObject.move()
RObject.moveAsync()
MSET RedissonClient.saveBuckets()
PERSIST RExpirable.clearExpire()
RExpirable.clearExpireAsync()
RExpirableReactive.clearExpire()
PEXPIRE RExpirable.expire()
RExpirable.expireAsync()
RExpirableReactive.expire()
PEXPIREAT RExpirable.expireAt()
RExpirable.expireAtAsync()
RExpirableReactive.expireAt()
PFADD RHyperLogLog.add()
RHyperLogLog.addAsync()
RHyperLogLogReactive.add()
RHyperLogLog.addAll()
RHyperLogLog.addAllAsync()
RHyperLogLogReactive.addAll()
PFCOUNT RHyperLogLog.count()
RHyperLogLog.countAsync()
RHyperLogLogReactive.count()
RHyperLogLog.countWith()
RHyperLogLog.countWithAsync()
RHyperLogLogReactive.countWith()
PFMERGE RHyperLogLog.mergeWith()
RHyperLogLog.mergeWithAsync()
RHyperLogLogReactive.mergeWith()
PING Node.ping()
NodesGroup.pingAll()
PSUBSCRIBE RPatternTopic.addListener()
PTTL RExpirable.remainTimeToLive()
RExpirable.remainTimeToLiveAsync()
RExpirableReactive.remainTimeToLive()
PUBLISH RTopic.publish
PUNSUBSCRIBE RPatternTopic.removeListener()
RANDOMKEY RKeys.randomKey()
RKeys.randomKeyAsync()
RKeysReactive.randomKey()
RENAME RObject.rename()
RObject.renameAsync()
RObjectReactive.rename()
RENAMENX RObject.renamenx()
RObject.renamenxAsync()
RObjectReactive.renamenx()
RPOP RDeque.pollLast()
RDeque.pollLastAsync()
RDequeReactive.pollLast()
RDeque.removeLast()
RDeque.removeLastAsync()
RDequeReactive.removeLast()
RPOPLPUSH RDeque.pollLastAndOfferFirstTo()
RDeque.pollLastAndOfferFirstToAsync()
RPUSH RList.add()
RList.addAsync()
RListReactive.add()
SADD RSet.add()
RSet.addAsync()
RSetReactive.add()
SCARD RSet.size()
RSet.sizeAsync()
RSetReactive.size()
SCRIPT EXISTS RScript.scriptExists()
RScript.scriptExistsAsync()
RScriptReactive.scriptExists()
SCRIPT FLUSH RScript.scriptFlush()
RScript.scriptFlushAsync()
RScriptReactive.scriptFlush()
SCRIPT KILL RScript.scriptKill()
RScript.scriptKillAsync()
RScriptReactive.scriptKill()
SCRIPT LOAD RScript.scriptLoad()
RScript.scriptLoadAsync()
RScriptReactive.scriptLoad()
SDIFFSTORE RSet.diff()
RSet.diffAsync()
RSetReactive.diff()
SELECT Config.setDatabase()
SET RBucket.set()
RBucket.setAsync()
RBucketReactive.set()
SETBIT RBitSet.set()
RBitSet.setAsync()
RBitSet.clear()
RBitSet.clearAsync()
SETEX RBucket.set()
RBucket.setAsync()
RBucketReactive.set()
SETNX RBucket.trySet()
RBucket.trySetAsync()
RBucketReactive.trySet()
SISMEMBER RSet.contains()
RSet.containsAsync()
RSetReactive.contains()
SINTERSTORE RSet.intersection()
RSet.intersectionAsync()
RSetReactive.intersection()
SINTER RSet.readIntersection()
RSet.readIntersectionAsync()
RSetReactive.readIntersection()
SMEMBERS RSet.readAll()
RSet.readAllAsync()
RSetReactive.readAll()
SMOVE RSet.move()
RSet.moveAsync()
RSetReactive.move()
SPOP RSet.removeRandom()
RSet.removeRandomAsync()
RSetReactive.removeRandom()
SREM RSet.remove()
RSet.removeAsync()
RSetReactive.remove()
SUBSCRIBE RTopic.addListener()
RTopicReactive.addListener()
SUNION RSet.readUnion()
RSet.readUnionAsync()
RSetReactive.readUnion()
SUNIONSTORE RSet.union()
RSet.unionAsync()
RSetReactive.union()
TTL RExpirable.remainTimeToLive()
RExpirable.remainTimeToLiveAsync()
RExpirableReactive.remainTimeToLive()
UNSUBSCRIBE RTopic.removeListener()
RTopicReactive.removeListener()
WAIT RBatch.syncSlavesRBatchReactive.syncSlaves()
ZADD RScoredSortedSet.add()
RScoredSortedSet.addAsync()
RScoredSortedSetReactive.add()
ZCARD RScoredSortedSet.size()
RScoredSortedSet.sizeAsync()
RScoredSortedSetReactive.size()
ZCOUNT RScoredSortedSet.count()
RScoredSortedSet.countAsync()
ZINCRBY RScoredSortedSet.addScore()
RScoredSortedSet.addScoreAsync()
RScoredSortedSetReactive.addScore()
ZLEXCOUNT RLexSortedSet.lexCount()
RLexSortedSet.lexCountAsync()
RLexSortedSetReactive.lexCount()
RLexSortedSet.lexCountHead()
RLexSortedSet.lexCountHeadAsync()
RLexSortedSetReactive.lexCountHead()
RLexSortedSet.lexCountTail()
RLexSortedSet.lexCountTailAsync()
RLexSortedSetReactive.lexCountTail()
ZRANGE RScoredSortedSet.valueRange()
RScoredSortedSet.valueRangeAsync()
RScoredSortedSetReactive.valueRange()
ZREVRANGE RScoredSortedSet.valueRangeReversed()
RScoredSortedSet.valueRangeReversedAsync()
RScoredSortedSetReactive.valueRangeReversed()
ZUNIONSTORE RScoredSortedSet.union()
RScoredSortedSet.unionAsync()
RScoredSortedSetReactive.union()
ZINTERSTORE RScoredSortedSet.intersection()
RScoredSortedSet.intersectionAsync()
RScoredSortedSetReactive.intersection()
ZRANGEBYLEX RLexSortedSet.lexRange()
RLexSortedSet.lexRangeAsync()
RLexSortedSetReactive.lexRange()
RLexSortedSet.lexRangeHead()
RLexSortedSet.lexRangeHeadAsync()
RLexSortedSetReactive.lexRangeHead()
RLexSortedSet.lexRangeTail()
RLexSortedSet.lexRangeTailAsync()
RLexSortedSetReactive.lexRangeTail()
ZRANGEBYSCORE RScoredSortedSet.valueRange()
RScoredSortedSet.valueRangeAsync()
RScoredSortedSetReactive.valueRange()
RScoredSortedSet.entryRange()
RScoredSortedSet.entryRangeAsync()
RScoredSortedSetReactive.entryRange()
TIME RedissonClient.getNodesGroup()
.getNode()
.time()
RedissonClient.getClusterNodesGroup()
.getNode()
.time()
ZRANK RScoredSortedSet.rank()
RScoredSortedSet.rankAsync()
RScoredSortedSetReactive.rank()
ZREM RScoredSortedSet.remove()
RScoredSortedSet.removeAsync()
RScoredSortedSetReactive.remove()
RScoredSortedSet.removeAll()
RScoredSortedSet.removeAllAsync()
RScoredSortedSetReactive.removeAll()
ZREMRANGEBYLEX RLexSortedSet.removeRangeByLex()
RLexSortedSet.removeRangeByLexAsync()
RLexSortedSetReactive.removeRangeByLex()
RLexSortedSet.removeRangeHeadByLex()
RLexSortedSet.removeRangeHeadByLexAsync()
RLexSortedSetReactive.removeRangeHeadByLex()
RLexSortedSet.removeRangeTailByLex()
RLexSortedSet.removeRangeTailByLexAsync()
RLexSortedSetReactive.removeRangeTailByLex()
ZREMRANGEBYLEX RScoredSortedSet.removeRangeByRank()
RScoredSortedSet.removeRangeByRankAsync()
RScoredSortedSetReactive.removeRangeByRank()
ZREMRANGEBYSCORE RScoredSortedSet.removeRangeByScore()
RScoredSortedSet.removeRangeByScoreAsync()
RScoredSortedSetReactive.removeRangeByScore()
ZREVRANGEBYSCORE RScoredSortedSet.entryRangeReversed()
RScoredSortedSet.entryRangeReversedAsync()
RScoredSortedSetReactive.entryRangeReversed()
RScoredSortedSet.valueRangeReversed()
RScoredSortedSet.valueRangeReversedAsync()
RScoredSortedSetReactive.valueRangeReversed()
ZREVRANK RScoredSortedSet.revRank()
RScoredSortedSet.revRankAsync()
RScoredSortedSetReactive.revRank()
ZSCORE RScoredSortedSet.getScore()
RScoredSortedSet.getScoreAsync()
RScoredSortedSetReactive.getScore()
SCAN RKeys.getKeys()
RKeysReactive.getKeys()
SSCAN RSet.iterator()
RSetReactive.iterator()
HSCAN RMap.keySet()
.iterator()
RMap.values()
.iterator()
RMap.entrySet()
.iterator()
RMapReactive.keyIterator()
RMapReactive.valueIterator()
RMapReactive.entryIterator()
ZSCAN RScoredSortedSet.iterator()
RScoredSortedSetReactive.iterator()

标签:queueId,Redisson,RMap,get,队列,RSet,开发,日常,RScoredSortedSet
From: https://www.cnblogs.com/kimber/p/17800405.html

相关文章

  • EasyDL平台的强大开发力量
    随着人工智能技术的不断发展,越来越多的企业和开发者开始关注如何快速开发出高效的AI应用。为了满足这一需求,越来越多的零门槛AI开发平台开始涌现。其中,百亿参数大模型ERNIE加持下的EasyDL平台备受瞩目。那么,这款平台究竟有多强呢?首先,我们要清楚一点:百亿参数大模型ERNIE是什么?ERNIE......
  • 智能合约开发-环境部署
    1.下载dotenv包yarnadddotenv导入require("dotenv).config()2.在.env中导入需要配置的信息,用于其它地方调用使用,例如: 3.调用使用方法process.env.参数名称例如: ......
  • 游戏开发进行中UE5引擎打不开后续
    游戏每次启动都有个问题:  之前我实现了插件里的接口,但是已启动,关于接口这一块的就消失了,有些函数还在但是却是自定义事件,不是接口里的,ClassSettings里面也提了  然后我把他改成了新的character class,然后在c++的接口新增一个函数,然后无法编译:   无法编译的报错......
  • 【FPGA】 3-8译码器 —— 组合逻辑 | 熟悉语法及开发环境
    文章目录1.设计输入2.分析综合3.功能仿真4.板爷调试继续熟悉基于vivado的FPGA开发流程。。学习一些新语法3-8译码器的应用我们接下来还会用到~创建工程观众老爷们别管了,咱板子也不一定一样~1.设计输入编码画框图,vivado支持较弱使用IP,我们今天暂时不用哦~添加DesignSource......
  • Android开发App回到桌面但不退出APP的实现
    方法1:Intentintent=newIntent();//创建Intent对象intent.setAction(Intent.ACTION_MAIN);//设置Intent动作intent.addCategory(Intent.CATEGORY_HOME);//设置Intent种类intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//标记context.startActivity(intent);方法2:......
  • 红外成像仪开发难点的兼容性问题
    飞讯教学篇:红外成像仪开发难点的兼容性问题红外成像技术是一种用于对物体表面进行无接触式测量得先进技术。它是基于物体与环境之间的热辐射,通过测量这种热辐射来实现对物体的成像。红外成像技术已经成为现代科技领域中一个不可或缺的工具,广泛应用于军事、医疗、安防等领域。然而,在......
  • 学习开发振弦采集模块的注意事项
    学习开发振弦采集模块的注意事项(三河凡科科技/飞讯教学)振弦采集模块是一种用来实时采集和处理振弦信号的电子设备,在工业、航空、医疗等领域都有广泛应用。学习开发振弦采集模块需要注意以下几点: 一、硬件选择首先需要选择适合自己开发的振弦采集模块硬件,这需要根据自己的应用场景......
  • 面向Three.js开发者的3D自动纹理化开发包
    DreamTexture.js是面向three.js开发者的 3D模型纹理自动生成与设置开发包,可以为webGL应用增加3D模型的快速自动纹理化能力。图一为原始模型,图二图三为贴图后的模型。提示词:city,Realistic,cinematic,Frontview,Gamescenegraph1、DreamTexture.js开发包内......
  • Opencascad开发(C++)-数据类型转换-Shape、Verterx和gp_pnt的转化
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录1、前言2、TopoDS_Shape与TopoDS_Vertex的转换2.1TopoDS_Shape到TopoDS_Vertex2.2TopoDS_Vertex到TopoDS_Shape3、TopoDS_Vertex与gp_Pnt3.1TopoDS_Vertex到gp_Pnt3.2gp_Pnt到TopoDS_Vertex1、前言在Open......
  • SpringBoot事件驱动开发
    应用启动过程生命周期事件感知(9大事件)、应用运行中事件感知(无数种)事件发布:ApplicationEventPublisherAware或注入:ApplicationEventMulticaster事件监听:组件+@EventListener场景:当用户登录后,我们需要为用户增加一个积分、随机获取一张优惠券、增加日志等,传统的开发模式......