Redis学习总结(基本数据类型 底层结构)

目录

redis基本数据类型,底层原理,应用场景

String**

sds预分配,扩容机制?

什么时候用哪个编码?

特殊情况

应用场景 - 一个键最大能存储512MB

分布式锁

计数器

存储token

 java jedis用法

List**

基本用法

底层结构

双向链表

​编辑

​编辑

压缩链表

什么时候用哪个底层结构?**

应用场景 - 列表最多可存储 2的32次方 - 1 元素 (4294967295, 每个列表可存储40多亿)。

消息队列

java redis用法

Set**

基本用法

底层结构

int数组

哈希表

什么时候用哪个数据结构?

应用场景 - 集合中最大的成员数为 2的32次方 - 1 (4294967295, 每个集合可存储40多亿个成员)。

共同粉丝,共同好友(交集)

java jedis用法

Zset**

数据结构

压缩链表

跳表

什么时候用跳表,什么时候用跳表?

应用场景

排行榜

java jedis用法

Hash**

数据结构

哈希表

压缩链表

什么时候用哈希表,什么时候用压缩链表?

应用场景 - 每个 hash 可以存储 2的32次方 - 1 键值对(40多亿)。

存储对象

java jedis用法

bitmap*

基本命令

java用法

hyperloglog*

基本命令

java用法

geospatial*

基本用法

java 用法

Streams

基本用法

java jedis用法

Bitfields

基本命令

官网目前没有提供jedis java用法


redis基本数据类型,底层原理,应用场景

String**

基本用法

SET存储字符串值。
SETNX仅在键不存在的情况下存储字符串值。用于实现锁。
GET检索字符串值。
MGET在单个操作中检索多个字符串值。

key - value键值对,底层数据结构是SDS简单动态字符。

struct SDS<T> {
	T capacity; // 数组容量   使用泛型表示的
	T len; // 数组长度      使用泛型表示的 
	byte flags; // 特殊标识位,不理睬它
	byte[] content; // 数组内容   字节数组
}

buf数组存储实际的字符串。len字段存储了buf的长度。这使得获得Redis字符串的长度是一个0(1)操作。free=capacity-len 存储可供使用的额外字节数。

详细来说的话,底层有三种编码方式,int,embstr,raw

其中int存储的是long型数据,其他两个都用sds,不过embstr编码的sds是最结构效率最快的。
应用场景。??

sds预分配,扩容机制?

字符串实际分配的空间 capacity 一般要高于实际字符串长度 len.

1、获取当前可用空间长度avail,若大于等于新增长度addlen,说明无需扩容,直接返回
2、若avail小于addlen,s的长度加上addlen小于1M(代码中的SDS_MAX_PREALLOC就是1M),那么按新长度的2倍扩容
3、若avail小于addlen,s的长度加上addlen大于1M,那么按新长度加1M

4、根据新长度选择sds类型,若sds类型和原类型相同,则调用s_realloc_usable,扩大柔性数组
5、如果sds类型和原类型不同,则调用s_malloc_usable,重新申请内存,把原buf内容移动到新位置
6、对新串的属性进行赋值,返回。

sds _sdsMakeRoomFor(sds s, size_t addlen, int greedy) {
    void *sh, *newsh;
    size_t avail = sdsavail(s);
    size_t len, newlen, reqlen;
    char type, oldtype = s[-1] & SDS_TYPE_MASK;
    int hdrlen;
    size_t usable;

    /* Return ASAP if there is enough space left. */
    if (avail >= addlen) return s;

    len = sdslen(s);
    sh = (char*)s-sdsHdrSize(oldtype);
    reqlen = newlen = (len+addlen);
    assert(newlen > len);   /* Catch size_t overflow */
    if (greedy == 1) {
        if (newlen < SDS_MAX_PREALLOC)
            newlen *= 2;
        else
            newlen += SDS_MAX_PREALLOC;
    }

    type = sdsReqType(newlen);

    /* Don't use type 5: the user is appending to the string and type 5 is
     * not able to remember empty space, so sdsMakeRoomFor() must be called
     * at every appending operation. */
    if (type == SDS_TYPE_5) type = SDS_TYPE_8;

    hdrlen = sdsHdrSize(type);
    assert(hdrlen + newlen + 1 > reqlen);  /* Catch size_t overflow */
    if (oldtype==type) {
        newsh = s_realloc_usable(sh, hdrlen+newlen+1, &usable);
        if (newsh == NULL) return NULL;
        s = (char*)newsh+hdrlen;
    } else {
        /* Since the header size changes, need to move the string forward,
         * and can't use realloc */
        newsh = s_malloc_usable(hdrlen+newlen+1, &usable);
        if (newsh == NULL) return NULL;
        memcpy((char*)newsh+hdrlen, s, len+1);
        s_free(sh);
        s = (char*)newsh+hdrlen;
        s[-1] = type;
        sdssetlen(s, len);
    }
    usable = usable-hdrlen-1;
    if (usable > sdsTypeMaxSize(type))
        usable = sdsTypeMaxSize(type);
    sdssetalloc(s, usable);
    return s;

什么时候用哪个编码?

数据类型       编码格式
19位数字int
大于19位数字embstr
大于44位数字raw
浮点数,普通字符串embstr
大于44位浮点数,普通字符串raw

如果长度小于44字节,则按embstr方式编码,否则按raw方式编码

#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char *ptr, size_t len) {
    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
        return createEmbeddedStringObject(ptr,len);
    else
        return createRawStringObject(ptr,len);
}

特殊情况

embstr仅是可读的,如果修改了之后,就会变成raw格式编码。

编码格式特点
int仅包含redisObject数据结构,直接将数据赋值给ptr
embstr包含redisObject以及sds数据结构,通过ptr指针连续存储在一起
raw包含redisObject以及sds数据结构,通过ptr指针链接,分开存储
struct RedisObject {
	int4 type; // 4bits
	int4 encoding; // 4bits
	int24 lru; // 24bits
	int32 refcount; // 4bytes
	void *ptr; // 8bytes,64-bit system
} robj;
不同的对象具有不同的类型 type(4bit),
同一个类型的 type 会有不同的存储形式encoding(4bit),
为了记录对象的 LRU 信息,使用了 24 个 bit 来记录 LRU 信息。
每个对象都有个引用计数,当引用计数为零时,对象就会被销毁,内存被回收。
ptr 指针将指向对象内容 (body) 的具体存储位置。

应用场景 - 一个键最大能存储512MB

分布式锁

  完整写法 - set lock xxx nx ex 5

redis> SETNX mykey "Hello"
(integer) 1
redis> SETNX mykey "World"
(integer) 0
redis> GET mykey
"Hello"
计数器
redis> SET mykey "10"
"OK"
redis> INCRBY mykey 5
(integer) 15
存储token
redis> SET mykey "Hello"
"OK"
redis> GET mykey
"Hello"
redis> SET anotherkey "will expire in a minute" EX 60
"OK"

 java jedis用法

package io.redis.examples;


import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.params.SetParams;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class StringExample {
  public void run() {
    try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) {

      String res1 = jedis.set("bike:1", "Deimos");
      System.out.println(res1); // OK
      String res2 = jedis.get("bike:1");
      System.out.println(res2); // Deimos

      Long res3 = jedis.setnx("bike:1", "bike");
      System.out.println(res3); // 0 (because key already exists)
      System.out.println(jedis.get("bike:1")); // Deimos (value is unchanged)
      String res4 = jedis.set("bike:1", "bike", SetParams.setParams().xx()); // set the value to "bike" if it
      // already
      // exists
      System.out.println(res4); // OK

      String res5 = jedis.mset("bike:1", "Deimos", "bike:2", "Ares", "bike:3", "Vanth");
      System.out.println(res5); // OK
      List<String> res6 = jedis.mget("bike:1", "bike:2", "bike:3");
      System.out.println(res6); // [Deimos, Ares, Vanth]

      jedis.set("total_crashes", "0");
      Long res7 = jedis.incr("total_crashes");
      System.out.println(res7); // 1
      Long res8 = jedis.incrBy("total_crashes", 10);
      System.out.println(res8); // 11

    }
  }
}

Redis Strings | Docs

redis数据结构源码分析——string_redis string 源码-CSDN博客

Redis底层数据结构之String_redis string 底层数据结构-CSDN博客

Redis进阶-string底层数据结构精讲-腾讯云开发者社区-腾讯云

List**

基本用法

LPUSH在列表的头部添加一个新元素;RPUSH添加到尾部。
LPOP从列表的头部删除并返回一个元素;RPOP做同样的事情,但是是从列表的尾部。
LLEN返回列表的长度。
LMOVE自动地将元素从一个列表移动到另一个列表。
LTRIM将列表缩减为指定的元素范围。

列表支持多个阻塞命令。例如:
BLPOP从列表的头部删除并返回一个元素。如果列表为空,则命令阻塞,直到元素变为可用或达到指定的超时。
BLMOVE自动地将元素从源列表移动到目标列表。如果源列表为空,则该命令将阻塞,直到有新的元素可用。

底层结构

底层有两种数据结构,双端链表和压缩链表

双向链表

无环,双向,头尾指针

typedef struct listNode {
    //前置节点
    struct listNode *prev;
    //后置节点
    struct listNode *next;
    //节点的值
    void *value;
} listNode;

在此基础上他还设计了list结构

typedef struct list {
    //链表头节点
    listNode *head;
    //链表尾节点
    listNode *tail;
    //节点值复制函数
    void *(*dup)(void *ptr);
    //节点值释放函数
    void (*free)(void *ptr);
    //节点值比较函数
    int (*match)(void *ptr, void *key);
    //链表节点数量
    unsigned long len;
} list;

优点:1.无环 2.查找速度快 

缺点:1.内存不连续,无法很好的利用cpu缓存 2.内存开销大

压缩链表

一种紧凑型数据结构,压缩链表字节数zlbytes,从首到尾字节数zltail,节点个数zllength,entries节点列表,zlend压缩列表结束符。entries包括前一个指针,编码方式int或string,数据data。

优点:

  • 一种内存紧凑型的数据结构,占用一块连续的内存空间

缺点:

  • 不能保存过多的元素,否则查询效率就会降低;
  • 新增或修改某个元素时,压缩列表占用的内存空间需要重新分配,甚至可能引发连锁更新的问题。

什么时候用哪个底层结构?**

当列表对象同时满足以下两个条件时,列表对象使用ziplist进行存储,否则用linkedlist存储。

  • 列表对象保存的所有字符串元素的长度小于64字节
  • 列表对象保存的元素数量小于512个。

应用场景 - 列表最多可存储 2的32次方 - 1 元素 (4294967295, 每个列表可存储40多亿)。

消息队列
> LPUSH msg_queue msg1 msg2 msg3
(integer) 3
这边往 key 为 msg_queue 的队列中插入了三个消息 msg1、msg2、msg3。
> RPOP msg_queue
"msg1"
> RPOP msg_queue
"msg2"
> RPOP msg_queue
"msg3"
> RPOP msg_queue
(nil)
Redis 提供了 BLPOP、BRPOP ,无数据的时候自动阻塞读取的命令,有新消息进入的时候,恢复消息取数

Redis使用List实现消息队列_redis list消息队列-CSDN博客

java redis用法

package io.redis.examples;

import org.junit.Test;
import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.args.ListDirection;
import java.util.List;
import static org.junit.Assert.*;

public class ListExample {
    public void run() {
        UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
        long res1 = jedis.lpush("bikes:repairs", "bike:1");
        System.out.println(res1);  // >>> 1

        long res2 = jedis.lpush("bikes:repairs", "bike:2");
        System.out.println(res2);  // >>> 2

        String res3 = jedis.rpop("bikes:repairs");
        System.out.println(res3);  // >>> bike:1

        String res4 = jedis.rpop("bikes:repairs");
        System.out.println(res4); // >>> bike:2

        long res5 = jedis.lpush("bikes:repairs", "bike:1");
        System.out.println(res5);  // >>> 1

        long res6 = jedis.lpush("bikes:repairs", "bike:2");
        System.out.println(res6);  // >>> 2

        String res7 = jedis.lpop("bikes:repairs");
        System.out.println(res7);  // >>> bike:2

        String res8 = jedis.lpop("bikes:repairs");
        System.out.println(res8);  // >>> bike:1

        long res9 = jedis.llen("bikes:repairs");
        System.out.println(res9);  // >>> 0

        long res10 = jedis.lpush("bikes:repairs", "bike:1");
        System.out.println(res10);  // >>> 1

        long res11 = jedis.lpush("bikes:repairs", "bike:2");
        System.out.println(res11);  // >>> 2

        String res12 = jedis.lmove("bikes:repairs", "bikes:finished", ListDirection.LEFT, ListDirection.LEFT);
        System.out.println(res12);  // >>> bike:2

        List<String> res13 = jedis.lrange("bikes:repairs", 0, -1);
        System.out.println(res13);  // >>> [bike:1]

        List<String> res14 = jedis.lrange("bikes:finished", 0, -1);
        System.out.println(res14);  // >>> [bike:2]

        long res15 = jedis.rpush("bikes:repairs", "bike:1");
        System.out.println(res15);  // >>> 1

        long res16 = jedis.rpush("bikes:repairs", "bike:2");
        System.out.println(res16);  // >>> 2

        long res17 = jedis.lpush("bikes:repairs", "bike:important_bike");
        System.out.println(res17);  // >>> 3

        List<String> res18 = jedis.lrange("bikes:repairs", 0, -1);
        System.out.println(res18);  // >>> [bike:important_bike, bike:1, bike:2]

        long res19 = jedis.rpush("bikes:repairs", "bike:1", "bike:2", "bike:3");
        System.out.println(res19);  // >>> 3

        long res20 = jedis.lpush("bikes:repairs", "bike:important_bike", "bike:very_important_bike");
        System.out.println(res20);  // >>> 5

        List<String> res21 = jedis.lrange("bikes:repairs", 0, -1);
        System.out.println(res21);  // >>> [bike:very_important_bike, bike:important_bike, bike:1, bike:2, bike:3]

        long res22 = jedis.rpush("bikes:repairs", "bike:1", "bike:2", "bike:3");
        System.out.println(res22);  // >>> 3

        String res23 = jedis.rpop("bikes:repairs");
        System.out.println(res23);  // >>> bike:3

        String res24 = jedis.lpop("bikes:repairs");
        System.out.println(res24);  // >>> bike:1

        String res25 = jedis.rpop("bikes:repairs");
        System.out.println(res25);  // >>> bike:2

        String res26 = jedis.rpop("bikes:repairs");
        System.out.println(res26);  // >>> null

        long res27 = jedis.lpush("bikes:repairs", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5");
        System.out.println(res27);  // >>> 5

        String res28 = jedis.ltrim("bikes:repairs", 0, 2);
        System.out.println(res28);  // >>> OK

        List<String> res29 = jedis.lrange("bikes:repairs", 0, -1);
        System.out.println(res29);  // >>> [bike:5, bike:4, bike:3]

        res27 = jedis.rpush("bikes:repairs", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5");
        System.out.println(res27);  // >>> 5

        res28 = jedis.ltrim("bikes:repairs", -3, -1);
        System.out.println(res2);  // >>> OK

        res29 = jedis.lrange("bikes:repairs", 0, -1);
        System.out.println(res29);  // >>> [bike:3, bike:4, bike:5]

        long res31 = jedis.rpush("bikes:repairs", "bike:1", "bike:2");
        System.out.println(res31);  // >>> 2

        List<String> res32 = jedis.brpop(1, "bikes:repairs");
        System.out.println(res32);  // >>> (bikes:repairs, bike:2)

        List<String>  res33 = jedis.brpop(1,"bikes:repairs");
        System.out.println(res33);  // >>> (bikes:repairs, bike:1)

        List<String>  res34 = jedis.brpop(1,"bikes:repairs");
        System.out.println(res34);  // >>> null

        long res35 = jedis.del("new_bikes");
        System.out.println(res35);  // >>> 0

        long res36 = jedis.lpush("new_bikes", "bike:1", "bike:2", "bike:3");
        System.out.println(res36);  // >>> 3

        String res37 = jedis.set("new_bikes", "bike:1");
        System.out.println(res37);  // >>> OK

        String res38 = jedis.type("new_bikes");
        System.out.println(res38);  // >>> string

        try {
            long res39  = jedis.lpush("new_bikes", "bike:2", "bike:3");
        } catch (Exception e) {
            e.printStackTrace();
            // >>> redis.clients.jedis.exceptions.JedisDataException:
            // >>> WRONGTYPE Operation against a key holding the wrong kind of value
        }

        jedis.lpush("bikes:repairs", "bike:1", "bike:2", "bike:3");
        System.out.println(res36);  // >>> 3

        boolean res40 = jedis.exists("bikes:repairs");
        System.out.println(res40);  // >>> true

        String res41 = jedis.lpop("bikes:repairs");
        System.out.println(res41);  // >>> bike:3

        String res42 = jedis.lpop("bikes:repairs");
        System.out.println(res42);  // >>> bike:2

        String res43 = jedis.lpop("bikes:repairs");
        System.out.println(res43);  // >>> bike:1

        boolean res44 = jedis.exists("bikes:repairs");
        System.out.println(res44);  // >>> false

        long res45 = jedis.del("bikes:repairs");
        System.out.println(res45);  // >>> 0

        long res46 = jedis.llen("bikes:repairs");
        System.out.println(res46);  // >>> 0

        String res47 = jedis.lpop("bikes:repairs");
        System.out.println(res47);  // >>> null

        long res48 = jedis.lpush("bikes:repairs", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5");
        System.out.println(res48);  // >>> 5

        String res49 = jedis.ltrim("bikes:repairs", 0, 2);
        System.out.println(res49);  // >>> OK

        List<String> res50 = jedis.lrange("bikes:repairs", 0, -1);
        System.out.println(res50);  // >>> [bike:5, bike:4, bike:3]
    }
}

Redis lists | Docs

redis list底层数据结构_redis底层是如何存储list列表的? csdn-CSDN博客

Set**

基本用法

SADD向集合添加一个新成员。
SREM从集合中删除指定的成员。
SISMEMBER测试字符串的集合成员关系。
SINTER返回两个或多个集合共有的成员的集合(即交集)。
SCARD返回集合的大小(即基数)。

无序不重复集合 ,

底层结构

int数组
typedef struct intset {
    //编码方式
    uint32_t encoding;//int16_t 2字节、int32_t 4字节和int64_t类型 8字节
    //集合中包含的元素数量
    uint32_t length;
    //保存元素的数组
    int8_t contents[];
} intset;

哈希表
typedef struct dictht {
    dictEntry **table;//哈希表数组
    unsigned long size;//哈希表大小
    unsigned long sizemask;//掩码大小,用于计算索引值,总是等于size-1
    unsigned long used;//哈希表中的已有节点数
} dictht;

注:table 是一个数组,其每个元素都是一个 dictEntry 对象。

什么时候用哪个数据结构?

 set-max-intset-entries的默认值是512,表示当Set对象的键值对数量大于该值时使用HashTable数据结构。

  •         当Set对象的值出现了非数字时,也会使用HashTable数据结构。
  •         当插入一个非数字时,数据结构从IntList转变为HashTable。
  •         当元素数量超过512时,数据结构从IntList转变为HashTable。

应用场景 - 集合中最大的成员数为 2的32次方 - 1 (4294967295, 每个集合可存储40多亿个成员)。

共同粉丝,共同好友(交集)
SINTER set1 set2

java jedis用法

package io.redis.examples;

import redis.clients.jedis.UnifiedJedis;
import org.junit.Test;
import java.util.List;
import java.util.Set;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertEquals;

public class SetsExample {

    public void run() {
        UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
        long res1 = jedis.sadd("bikes:racing:france", "bike:1");
        System.out.println(res1);  // >>> 1

        long res2 = jedis.sadd("bikes:racing:france", "bike:1");
        System.out.println(res2);  // >>> 0

        long res3 = jedis.sadd("bikes:racing:france", "bike:2", "bike:3");
        System.out.println(res3);  // >>> 2

        long res4 = jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");
        System.out.println(res4);  // >>> 2

        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
        jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");

        boolean res5 = jedis.sismember("bikes:racing:usa", "bike:1");
        System.out.println(res5);  // >>> true

        boolean res6 = jedis.sismember("bikes:racing:usa", "bike:2");
        System.out.println(res6);  // >>> false

        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
        jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");

        Set<String> res7 = jedis.sinter("bikes:racing:france", "bikes:racing:usa");
        System.out.println(res7);  // >>> [bike:1]

        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");

        long res8 = jedis.scard("bikes:racing:france");
        System.out.println(res8);  // >>> 3

        long res9 = jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
        System.out.println(res9);  // >>> 3

        Set<String> res10 = jedis.smembers("bikes:racing:france");
        System.out.println(res10);  // >>> [bike:1, bike:2, bike:3]

        boolean res11 = jedis.sismember("bikes:racing:france", "bike:1");
        System.out.println(res11);  // >>> true

        List<Boolean> res12 = jedis.smismember("bikes:racing:france", "bike:2", "bike:3", "bike:4");
        System.out.println(res12);  // >>> [true,true,false]

        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
        jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");

        Set<String> res13 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa");
        System.out.println(res13);  // >>> [bike:2, bike:3]

        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
        jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");
        jedis.sadd("bikes:racing:italy", "bike:1", "bike:2", "bike:3", "bike:4");

        Set<String> res14 = jedis.sinter("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
        System.out.println(res14);  // >>> [bike:1]

        Set<String> res15 = jedis.sunion("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
        System.out.println(res15);  // >>> [bike:1, bike:2, bike:3, bike:4]

        Set<String> res16 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
        System.out.println(res16);  // >>> []

        Set<String> res17 = jedis.sdiff("bikes:racing:usa", "bikes:racing:france");
        System.out.println(res17);  // >>> [bike:4]

        Set<String> res18 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa");
        System.out.println(res18);  // >>> [bike:2, bike:3]

        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5");

        long res19 = jedis.srem("bikes:racing:france", "bike:1");
        System.out.println(res18);  // >>> 1

        String res20 = jedis.spop("bikes:racing:france");
        System.out.println(res20);  // >>> bike:3

        Set<String> res21 = jedis.smembers("bikes:racing:france");
        System.out.println(res21);  // >>> [bike:2, bike:4, bike:5]

        String res22 = jedis.srandmember("bikes:racing:france");
        System.out.println(res22);  // >>> bike:4

        jedis.close();
    }
}

Redis sets | Docs

Redis数据结构:Set类型全面解析-腾讯云开发者社区-腾讯云

Redis高级之底层源码4——Set数据结构底层源码分析-CSDN博客

Zset**

有序不重复集合,底层跳表或压缩列表

数据结构

压缩链表

跟list压缩链表一致

跳表
typedef struct zskiplistNode {
    robj *obj;
    double score;
    struct zskiplistNode *backward;
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned int span;
    } level[];
} zskiplistNode;

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;
    unsigned long length;
    int level;
} zskiplist;
  • zskiplistNode 结构体表示跳跃表中的一个节点。包含元素对象(obj)、分数(score)、指向前一个节点的指针(backward)和一个包含多个层的数组(level)。每一层都包含一个指向下一个节点的指针(forward)和一个表示当前节点到下一个节点的跨度(span)
  •  zskiplist 结构体表示一个跳跃表,包含头节点(header)、尾节点(tail)、跳跃表中的节点数量(length)和当前跳跃表的最大层数(level)

什么时候用跳表,什么时候用跳表?

这主要取决于两个配置参数:zset-max-ziplist-entries (默认值为128 单位:个) 和 zset-max-ziplist-value (默认值为64,单位:字节)。

[value,score]键值对数量少于128个;每个元素的长度小于64字节。

应用场景

排行榜
# 查询score评分在某个范围内的数据,从小到大排序,min 和 max 可以是 -inf 和 +inf来表示无穷小和无穷大,withscores加上他,连着评分一起查出
zrangebyscore <key> <min> <max> [withscores] [limit offset count]

使用 Redis Zset 有序集合实现排行榜功能(SpringBoot环境)_redis实时排行榜-CSDN博客

java jedis用法

package io.redis.examples;

import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.resps.Tuple;


public class SortedSetsExample {

  public void run() {

    UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");


    long res1 = jedis.zadd("racer_scores", 10d, "Norem");
    System.out.println(res1); // >>> 1

    long res2 = jedis.zadd("racer_scores", 12d, "Castilla");
    System.out.println(res2); // >>> 1

    long res3 = jedis.zadd("racer_scores", new HashMap<String,Double>() {{
      put("Sam-Bodden", 8d);
      put("Royce", 10d);
      put("Ford", 6d);
      put("Prickett", 14d);
      put("Castilla", 12d);
    }});
    System.out.println(res3); // >>> 4

    List<String> res4 = jedis.zrange("racer_scores", 0, -1);
    System.out.println(res4); // >>> [Ford, Sam-Bodden, Norem, Royce, Castil, Castilla, Prickett]

    List<String> res5 = jedis.zrevrange("racer_scores", 0, -1);
    System.out.println(res5); // >>> [Prickett, Castilla, Castil, Royce, Norem, Sam-Bodden, Ford]

    List<Tuple> res6 = jedis.zrangeWithScores("racer_scores", 0, -1);
    System.out.println(res6); // >>> [[Ford,6.0], [Sam-Bodden,8.0], [Norem,10.0], [Royce,10.0], [Castil,12.0], [Castilla,12.0], [Prickett,14.0]]

    List<String> res7 = jedis.zrangeByScore("racer_scores", Double.MIN_VALUE, 10d);
    System.out.println(res7); // >>> [Ford, Sam-Bodden, Norem, Royce]

    long res8 = jedis.zrem("racer_scores", "Castilla");
    System.out.println(res8); // >>> 1

    long res9 = jedis.zremrangeByScore("racer_scores", Double.MIN_VALUE, 9d);
    System.out.println(res9); // >>> 2

    List<String> res10 = jedis.zrange("racer_scores", 0, -1);
    System.out.println(res10); // >>> [Norem, Royce, Prickett]


    long res11 = jedis.zrank("racer_scores", "Norem");
    System.out.println(res11); // >>> 0

    long res12 = jedis.zrevrank("racer_scores", "Norem");
    System.out.println(res12); // >>> 2

    long res13 = jedis.zadd("racer_scores", new HashMap<String,Double>() {{
      put("Norem", 0d);
      put("Sam-Bodden", 0d);
      put("Royce", 0d);
      put("Ford", 0d);
      put("Prickett", 0d);
      put("Castilla", 0d);
    }});
    System.out.println(res13); // >>> 3

    List<String> res14 = jedis.zrange("racer_scores", 0, -1);
    System.out.println(res14); // >>> [Castilla, Ford, Norem, Prickett, Royce, Sam-Bodden]

    List<String> res15 = jedis.zrangeByLex("racer_scores", "[A", "[L");
    System.out.println(res15); // >>> [Castilla, Ford]

    long res16 = jedis.zadd("racer_scores", 100d, "Wood");
    System.out.println(res16); // >>> 1

    long res17 = jedis.zadd("racer_scores", 100d, "Henshaw");
    System.out.println(res17); // >>> 1

    long res18 = jedis.zadd("racer_scores", 100d, "Henshaw");
    System.out.println(res18); // >>> 0

    double res19 = jedis.zincrby("racer_scores", 50d, "Wood");
    System.out.println(res19); // >>> 150.0

    double res20 = jedis.zincrby("racer_scores", 50d, "Henshaw");
    System.out.println(res20); // >>> 200.0
  }
}

Redis sorted sets | Docs

https://www.cnblogs.com/hld123/p/18074778

redis的基础底层篇 zset的详解_zset底层结构-CSDN博客

Redis底层数据结构详解-腾讯云开发者社区-腾讯云

Hash**

key-value结构 底层哈希表或压缩链表

数据结构

哈希表

与上面一致

压缩链表

与上面一致

什么时候用哈希表,什么时候用压缩链表?

在redis6中哈希对象报错的键值对个数要小于512,所有的键值对的键和值的字符串长度都小于64个字节时用ziplist否则用hashtable。

注意:ziplist可以升级为hashtable,但hashtable不能降级为ziplist,在节省内存空间方面哈希表是没有压缩列表高效的!

应用场景 - 每个 hash 可以存储 2的32次方 - 1 键值对(40多亿)。

存储对象
redis 127.0.0.1:6379> HMSET user:1 username redis.net.cn password redis.net.cn points 200
OK
redis 127.0.0.1:6379> HGETALL user:1
1) "username"
2) "redis.net.cn"
3) "password"
4) "redis.net.cn"
5) "points"
6) "200"

java jedis用法

package io.redis.examples;

import redis.clients.jedis.UnifiedJedis;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HashExample {
  public void run() {
    try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) {

      Map<String, String> bike1 = new HashMap<>();
      bike1.put("model", "Deimos");
      bike1.put("brand", "Ergonom");
      bike1.put("type", "Enduro bikes");
      bike1.put("price", "4972");

      Long res1 = jedis.hset("bike:1", bike1);
      System.out.println(res1); // 4

      String res2 = jedis.hget("bike:1", "model");
      System.out.println(res2); // Deimos

      String res3 = jedis.hget("bike:1", "price");
      System.out.println(res3); // 4972

      Map<String, String> res4 = jedis.hgetAll("bike:1");
      System.out.println(res4); // {type=Enduro bikes, brand=Ergonom, price=4972, model=Deimos}


      List<String> res5 = jedis.hmget("bike:1", "model", "price");
      System.out.println(res5); // [Deimos, 4972]


      Long res6 = jedis.hincrBy("bike:1", "price", 100);
      System.out.println(res6); // 5072
      Long res7 = jedis.hincrBy("bike:1", "price", -100);
      System.out.println(res7); // 4972


      Long res8 = jedis.hincrBy("bike:1:stats", "rides", 1);
      System.out.println(res8); // 1
      Long res9 = jedis.hincrBy("bike:1:stats", "rides", 1);
      System.out.println(res9); // 2
      Long res10 = jedis.hincrBy("bike:1:stats", "rides", 1);
      System.out.println(res10); // 3
      Long res11 = jedis.hincrBy("bike:1:stats", "crashes", 1);
      System.out.println(res11); // 1
      Long res12 = jedis.hincrBy("bike:1:stats", "owners", 1);
      System.out.println(res12); // 1
      String res13 = jedis.hget("bike:1:stats", "rides");
      System.out.println(res13); // 3
      List<String> res14 = jedis.hmget("bike:1:stats", "crashes", "owners");
      System.out.println(res14); // [1, 1]

    }
  }
}

Redis hashes | Docs

Redis底层数据结构之Hash_redis hash底层结构-CSDN博客

bitmap*

位图不是一种实际的数据类型,而是在String类型上定义的一组面向位的操作,它被视为位向量。由于字符串是二进制安全的blob,其最大长度为512 MB,因此它们适合设置最多2^32个不同的位。

基本命令

SETBIT将给定偏移量处的位设置为0或1。
GETBIT返回给定偏移量处的位的值。

java用法

package io.redis.examples;

import org.junit.Assert;
import org.junit.Test;
import redis.clients.jedis.UnifiedJedis;

public class BitMapsExample {

    public void run() {
        UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");



        boolean res1 = jedis.setbit("pings:2024-01-01-00:00", 123, true);
        System.out.println(res1); // >>> false

        boolean res2 = jedis.getbit("pings:2024-01-01-00:00", 123);
        System.out.println(res2); // >>> true

        boolean res3 = jedis.getbit("pings:2024-01-01-00:00", 456);
        System.out.println(res3); // >>> false


        long res4 = jedis.bitcount("pings:2024-01-01-00:00");
        System.out.println(res4); // >>> 1

    }
}

Redis bitmaps | Docs

hyperloglog*

HyperLogLog是一种概率数据结构,用于估计集合的基数。
HyperLogLog是一种概率数据结构,用于估计集合的基数。作为一种概率数据结构,HyperLogLog以完美的准确性换取有效的空间利用。
Redis HyperLogLog实现最多使用12 KB,标准误差为0.81%。

基本命令

PFADD向HyperLogLog添加一个项目。
PFCOUNT返回集合中项目数量的估计值。
PFMERGE将两个或多个hyperloglog合并为一个。

java用法

package io.redis.examples;

import org.junit.Assert;
import org.junit.Test;
import redis.clients.jedis.UnifiedJedis;

public class HyperLogLogExample {

    public void run() {
        UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");


        long res1 = jedis.pfadd("bikes", "Hyperion", "Deimos", "Phoebe", "Quaoar");
        System.out.println(res1); // >>> 1

        long res2 = jedis.pfcount("bikes");
        System.out.println(res2); // >>> 4

        long res3 = jedis.pfadd("commuter_bikes", "Salacia", "Mimas", "Quaoar");
        System.out.println(res3); // >>> 1

        String res4 = jedis.pfmerge("all_bikes", "bikes", "commuter_bikes");
        System.out.println(res4); // >>> OK


        long res5 = jedis.pfcount("all_bikes");
        System.out.println(res5); // >>> 6
    }
}

HyperLogLog | Docs

geospatial*

Redis地理空间索引允许您存储坐标并搜索它们。这种数据结构对于在给定半径或边界框内查找附近的点非常有用。

基本用法

GEOADD将位置添加到给定的地理空间索引(注意,使用此命令时经度在纬度之前)。
GEOSEARCH返回具有给定半径或边界框的位置。

java 用法

package io.redis.examples;

import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.args.GeoUnit;
import redis.clients.jedis.resps.GeoRadiusResponse;

import java.util.List;
import java.util.stream.Collectors;

import static org.junit.Assert.assertEquals;

public class GeoExample {
  public void run() {
    try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) {

      long res1 = jedis.geoadd("bikes:rentable", -122.27652, 37.805186, "station:1");
      System.out.println(res1); // 1

      long res2 = jedis.geoadd("bikes:rentable", -122.2674626, 37.8062344, "station:2");
      System.out.println(res2); // 1

      long res3 = jedis.geoadd("bikes:rentable", -122.2469854, 37.8104049, "station:3");
      System.out.println(res2); // 1


      List<GeoRadiusResponse> res4 = jedis.geosearch(
          "bikes:rentable",
          new GeoCoordinate(-122.27652, 37.805186),
          5,
          GeoUnit.KM
      );
      List<String> members = res4.stream() //
          .map(GeoRadiusResponse::getMemberByString) //
          .collect(Collectors.toList());
      System.out.println(members); // [station:1, station:2, station:3]

    }
  }
}

Redis geospatial | Docs

Streams

Redis流是一种数据结构,它的行为类似于仅追加日志,但也实现了一些操作来克服典型的仅追加日志的一些限制。其中包括O(1)时间内的随机访问和复杂的消费策略,例如消费者群体。您可以使用流来实时记录和同时联合事件。Redis流用例包括:

  • 事件溯源(例如,跟踪用户操作、点击等)
  • 传感器监控(例如,现场设备的读数)
  • 通知(例如,将每个用户的通知记录存储在单独的流中)

基本用法

XADD向流添加一个新条目。
XREAD读取一个或多个条目,从给定位置开始,并在时间上向前移动。
XRANGE返回两个提供的条目id之间的条目范围。
XLEN返回流的长度。

java jedis用法

package io.redis.examples;

import redis.clients.jedis.StreamEntryID;
import redis.clients.jedis.UnifiedJedis;


public class StreamsExample {

  public void run(){

    UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");


    StreamEntryID res1 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","30.2");put("position","1");put("location_id","1");}} , XAddParams.xAddParams());

    System.out.println(res1); // >>> 1701760582225-0

    StreamEntryID res2 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Norem");put("speed","28.8");put("position","3");put("location_id","1");}} , XAddParams.xAddParams());

    System.out.println(res2); // >>> 1701760582225-1

    StreamEntryID res3 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Prickett");put("speed","29.7");put("position","2");put("location_id","1");}} , XAddParams.xAddParams());

    System.out.println(res3); // >>> 1701760582226-0


    List<StreamEntry> res4 = jedis.xrange("race:france","1701760582225-0","+",2);

    System.out.println(res4); // >>> [1701760841292-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701760841292-1 {rider=Norem, speed=28.8, location_id=1, position=3}]

    List<Map.Entry<String, List<StreamEntry>>> res5= jedis.xread(XReadParams.xReadParams().block(300).count(100),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}});
    System.out.println(
      res5
    ); // >>> [race:france=[1701761996660-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701761996661-0 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701761996661-1 {rider=Prickett, speed=29.7, location_id=1, position=2}]]

    StreamEntryID res6 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","29.9");put("position","2");put("location_id","1");}} , XAddParams.xAddParams());
    System.out.println(res6); // >>> 1701762285679-0

    long res7 = jedis.xlen("race:france");
    System.out.println(res7); // >>> 4

    StreamEntryID res8 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Castilla");}},XAddParams.xAddParams().id("0-1"));
    System.out.println(res8); // >>> 0-1

    StreamEntryID res9 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-2"));
    System.out.println(res9); // >>> 0-2

    try {
      StreamEntryID res10 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Prickett");}},XAddParams.xAddParams().id("0-1"));
      System.out.println(res10); // >>> 0-1
    }
    catch (JedisDataException e){
      System.out.println(e); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item
    }

    StreamEntryID res11 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-*"));
    System.out.println(res11);

    List<StreamEntry> res12 = jedis.xrange("race:france","-","+");
    System.out.println(
      res12
    ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}]

    List<StreamEntry> res13 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000),String.valueOf(System.currentTimeMillis()+1000));
    System.out.println(
      res13
    ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}]

    List<StreamEntry> res14 = jedis.xrange("race:france","-","+",2);
    System.out.println(res14); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]

    List<StreamEntry> res15 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000)+"-0","+",2);
    System.out.println(res15); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]

    List<StreamEntry> res16 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()+1000)+"-0","+",2);
    System.out.println(res16); // >>> []

    List<StreamEntry> res17 = jedis.xrevrange("race:france","+","-",1);
    System.out.println(res17); // >>> [1701765218592-0 {rider=Castilla, speed=29.9, location_id=1, position=2}]

    List<Map.Entry<String, List<StreamEntry>>> res18= jedis.xread(XReadParams.xReadParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}});
    System.out.println(
      res18
    ); // >>> [race:france=[1701765384638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701765384638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]]

    String res19 = jedis.xgroupCreate("race:france","france_riders",StreamEntryID.LAST_ENTRY,false);
    System.out.println(res19); // >>> OK

    String res20 = jedis.xgroupCreate("race:italy","italy_riders",StreamEntryID.LAST_ENTRY,true);
    System.out.println(res20); // >>> OK

    StreamEntryID id1 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Castilaa");}},XAddParams.xAddParams());
    StreamEntryID id2 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Royce");}},XAddParams.xAddParams());
    StreamEntryID id3 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Sam-Bodden");}},XAddParams.xAddParams());
    StreamEntryID id4 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Prickett");}},XAddParams.xAddParams());
    StreamEntryID id5 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Norem");}},XAddParams.xAddParams());

    List<Map.Entry<String, List<StreamEntry>>> res21 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}});
    System.out.println(res21); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]]

    List<Map.Entry<String, List<StreamEntry>>> res22 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}});
    System.out.println(res22); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]]

    long res23 = jedis.xack("race:italy","italy_riders",id1);
    System.out.println(res23); // >>> 1

    List<Map.Entry<String, List<StreamEntry>>> res24 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}});
    System.out.println(res24); // >>> [race:italy=[]]

    List<Map.Entry<String, List<StreamEntry>>> res25 = jedis.xreadGroup("italy_riders","Bob", XReadGroupParams.xReadGroupParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}});
    System.out.println(res25); // >>> [race:italy=[1701767632261-1 {rider=Royce}, 1701767632262-0 {rider=Sam-Bodden}]]

    StreamPendingSummary res26 = jedis.xpending("race:italy","italy_riders");
    System.out.println(res26.getConsumerMessageCount()); // >>> {Bob=2}

    List<StreamPendingEntry> res27 = jedis.xpending("race:italy","italy_riders",XPendingParams.xPendingParams().start(StreamEntryID.MINIMUM_ID).end(StreamEntryID.MAXIMUM_ID).count(10));
    System.out.println(res27); // >>> [1701768567412-1 Bob idle:0 times:1, 1701768567412-2 Bob idle:0 times:1]

    List<StreamEntry> res28 = jedis.xrange("race:italy",id2.toString(),id2.toString());
    System.out.println(res28); // >>> [1701768744819-1 {rider=Royce}]

    List<StreamEntry> res29 = jedis.xclaim("race:italy","italy_riders","Alice", 0L, XClaimParams.xClaimParams().time(60000),id2);
    System.out.println(res29); // >>> [1701769004195-1 {rider=Royce}]

    Map.Entry<StreamEntryID, List<StreamEntry>> res30 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID("0-0"),XAutoClaimParams.xAutoClaimParams().count(1));
    System.out.println(res30); // >>> [1701769266831-2=[1701769266831-1 {rider=Royce}]

    Map.Entry<StreamEntryID, List<StreamEntry>> res31 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID(id2.toString()),XAutoClaimParams.xAutoClaimParams().count(1));
    System.out.println(res31); // >>> [0-0=[1701769605847-2 {rider=Sam-Bodden}]

    StreamInfo res32 = jedis.xinfoStream("race:italy");
    System.out.println(
      res32.getStreamInfo()
    ); // >>> {radix-tree-keys=1, radix-tree-nodes=2, entries-added=5, length=5, groups=1, max-deleted-entry-id=0-0, first-entry=1701769637612-0 {rider=Castilaa}, last-generated-id=1701769637612-4, last-entry=1701769637612-4 {rider=Norem}, recorded-first-entry-id=1701769637612-0}

    List<StreamGroupInfo> res33 = jedis.xinfoGroups("race:italy");
    for (StreamGroupInfo a : res33){
      System.out.println(
        a.getGroupInfo()
      ); // >>> {last-delivered-id=1701770253659-0, lag=2, pending=2, name=italy_riders, consumers=2, entries-read=3}
    }

    List<StreamConsumersInfo> res34 = jedis.xinfoConsumers("race:italy","italy_riders");
    for (StreamConsumerInfo a : res34){
      System.out.println(
        a.getConsumerInfo()
      ); // {inactive=1, idle=1, pending=1, name=Alice} , {inactive=3, idle=3, pending=1, name=Bob}
    }

    jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Jones");}},XAddParams.xAddParams().maxLen(10));
    jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Wood");}},XAddParams.xAddParams().maxLen(10));
    jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Henshaw");}},XAddParams.xAddParams().maxLen(10));
    long res35 = jedis.xlen("race:italy");
    System.out.println(res35); // >>> 8

    List<StreamEntry> res36 = jedis.xrange("race:italy","-","+");
    System.out.println(res36); // >>> [1701771219852-0 {rider=Castilaa}, 1701771219852-1 {rider=Royce}, 1701771219853-0 {rider=Sam-Bodden}, 1701771219853-1 {rider=Prickett}, 1701771219853-2 {rider=Norem}, 1701771219858-0 {rider=Jones}, 1701771219858-1 {rider=Wood}, 1701771219859-0 {rider=Henshaw}]

    StreamEntryID id6 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Smith");}},XAddParams.xAddParams().maxLen(2));

    List<StreamEntry> res37 = jedis.xrange("race:italy","-","+");
    System.out.println(res37); // >>> [1701771067332-1 {rider=Henshaw}, 1701771067332-2 {rider=Smith}]

    long res38 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10).exactTrimming());
    System.out.println(res38); /// >>> 0

    long res39 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10));
    System.out.println(res39); /// >>> 0

    List<StreamEntry> res40 = jedis.xrange("race:italy","-","+");
    System.out.println(res40); // >>> [1701771356428-2 {rider=Henshaw}, 1701771356429-0 {rider=Smith}]

    long res41 = jedis.xdel("race:italy",id6);
    System.out.println(res41); // >>> 1

    List<StreamEntry> res42 = jedis.xrange("race:italy","-","+");
    System.out.println(res42); // >>> [1701771517639-1 {rider=Henshaw}]
  }

}

Redis Streams | Docs

Bitfields

Redis位域允许您设置、递增和获取任意位长度的整数值。例如,您可以操作从无符号1位整数到有符号63位整数的任何整数。
这些值使用二进制编码的Redis字符串存储。位字段支持原子读、写和自增操作,这使得它们成为管理计数器和类似数值的好选择。

基本命令

BITFIELD自动设置、递增和读取一个或多个值。
BITFIELD_RO是BITFIELD的只读变体。

官网目前没有提供jedis java用法

Redis bitfields | Docs

redis/src/t_string.c at 6.0.0 · redis/redis · GitHub

  • 13
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低调$(生活)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值