您当前的位置: 首页 >  redis

梁云亮

暂无认证

  • 3浏览

    0关注

    1211博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Redis 基本数据类型汇总

梁云亮 发布时间:2022-10-05 12:54:20 ,浏览量:3

Redis键(key)
keys *查看当前库所有key    (匹配:keys *1)
exists key判断某个key是否存在
type key 查看你的key是什么类型
del key       删除指定的key数据
unlink key   根据value选择非阻塞删除
move key 2 
rename age aa
renamenx age abc
仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。
expire key 10   10秒钟:为给定的key设置过期时间
ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期

select命令切换数据库
dbsize查看当前数据库的key的数量
flushdb清空当前库
flushall通杀全部库
3.2 字符串(String)

String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。

String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。

String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M

序号命令及描述1SET key value 设置指定 key 的值2GET key 获取指定 key 的值。3GETRANGE key start end 返回 key 中字符串值的子字符4GETSET key value 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。5GETBIT key offset 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。6[MGET key1 key2…] 获取所有(一个或多个)给定 key 的值。7SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。8SETEX key seconds value 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。9SETNX key value 只有在 key 不存在时设置 key 的值。10SETRANGE key offset value 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。11STRLEN key 返回 key 所储存的字符串值的长度。12[MSET key value key value …] 同时设置一个或多个 key-value 对。13[MSETNX key value key value …] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。14PSETEX key milliseconds value 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。15INCR key 将 key 中储存的数字值增一。16INCRBY key increment 将 key 所储存的值加上给定的增量值(increment) 。17INCRBYFLOAT key increment 将 key 所储存的值加上给定的浮点增量值(increment) 。18DECR key 将 key 中储存的数字值减一。19DECRBY key decrement key 所储存的值减去给定的减量值(decrement) 。20APPEND key value 如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾。

语法:[ex|px]

image-20211207121322554

set   添加键值对
*NX:当数据库中key不存在时,可以将key-value添加数据库
*XX:当数据库中key存在时,可以将key-value添加数据库,与NX参数互斥
*EX:key的超时秒数
*PX:key的超时毫秒数,与EX互斥

get   查询对应键值
append  将给定的 追加到原值的末尾
strlen  获得值的长度
setnx  只有在 key 不存在时    设置 key 的值

incr  
将 key 中储存的数字值增1
只能对数字值操作,如果为空,新增值为1
decr  
将 key 中储存的数字值减1
只能对数字值操作,如果为空,新增值为-1
incrby / decrby  将 key 中储存的数字值增减。自定义步长。

mset       ..... 
同时设置一个或多个 key-value对  
mget     .....
同时获取一个或多个 value  
msetnx      ..... 
同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。原子性,有一个失败则都失败

getrange    
获得值的范围,类似java中的substring,前包,后包
setrange    
用   覆写所储存的字符串值,从开始(索引从0开始)。

setex    
设置键值的同时,设置过期时间,单位秒。
getset   
以新换旧,设置了新值同时获得旧值,会设置过期时间-1。

String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配.

image-20211207121415978

如图中所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。

pom.xml


    redis.clients
    jedis
    3.7.1
    
        
            org.apache.commons
            commons-pool2
        
    


    org.apache.commons
    commons-pool2
    2.11.1

public class RedisDemo {

    @Test
    public void str1(){
        Jedis j = new Jedis("localhost", 6379, 10000);
        j.auth("123456");
        String p = j.ping();
        System.out.println(p);
        //j.flushAll();
        //j.flushDB();
        //j.mset("m1","100","m2","200","m3","400");
        //j.expire("m1",1800l);
        for (String key : j.keys("*")) {
            System.out.println(j.get(key));
        }

        System.out.println(j.exists("name"));
        System.out.println(j.del("name"));
        System.out.println(j.dbSize());
        System.out.println(j.ttl("m1"));
        System.out.println(j.type("m1"));
    }

    private Jedis jedis;
    @BeforeEach
    public void init(){
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

        JedisPool pool = new JedisPool(poolConfig, "localhost", 6379, 10000, "123456");
        jedis = pool.getResource();
    }
    @AfterEach
    public void close(){
        jedis.close();
    }

    @Test
    public void str2(){
        System.out.println(jedis.ttl("m1"));
        for(String k : jedis.keys("m*")){
            System.out.println(jedis.get(k));
        }
    }

    @Test
    public void test1() throws InterruptedException {
        System.out.println("清空数据:" + jedis.flushDB());
        System.out.println("判断某个键是否存在:" + jedis.exists("username"));
        System.out.println("新增的键值对:" + jedis.set("username", "wukong"));
        System.out.println("是否存在:" + jedis.exists("name"));
        System.out.println("新增的键值对:" + jedis.set("password", "password"));
        Set keys = jedis.keys("*");
        System.out.println("系统中所有的键如下:" + keys);
        System.out.println("删除键password:" + jedis.del("password"));
        System.out.println("判断键password是否存在:" + jedis.exists("password"));
        System.out.println("设置键username的过期时间为5s:" + jedis.expire("username", 5));
        TimeUnit.SECONDS.sleep(2);
        System.out.println("查看键username的剩余生存时间:" + jedis.ttl("username"));
        System.out.println("移除键username的生存时间:" + jedis.persist("username"));
        System.out.println("查看键username的剩余生存时间:" + jedis.ttl("username"));
        System.out.println("查看键username所存储的值的类型:" + jedis.type("username"));
    }

    @Test
    public void test2() throws InterruptedException {
        // 字符串  string 的 操作
        jedis.flushDB();
        System.out.println("===========增加数据===========");
        System.out.println(jedis.set("key1", "value1"));
        System.out.println(jedis.set("key2", "value2"));
        System.out.println(jedis.set("key3", "value3"));
        System.out.println("删除键key2:" + jedis.del("key2"));
        System.out.println("获取键key2:" + jedis.get("key2"));
        System.out.println("修改key1:" + jedis.set("key1", "value1Changed"));
        System.out.println("获取key1的值:" + jedis.get("key1"));
        System.out.println("在key3后面加入值:" + jedis.append("key3", "End"));
        System.out.println("key3的值:" + jedis.get("key3"));
        System.out.println("增加多个键值对:" + jedis.mset("key01", "value01", "key02", "value02", "key03", "value03"));
        System.out.println("获取多个键值对:" + jedis.mget("key01", "key02", "key03"));
        System.out.println("获取多个键值对:" + jedis.mget("key01", "key02", "key03", "key04"));
        System.out.println("删除多个键值对:" + jedis.del("key01", "key02"));
        System.out.println("获取多个键值对:" + jedis.mget("key01", "key02", "key03"));

        jedis.flushDB();
        System.out.println("===========新增键值对防止覆盖原先值==============");
        System.out.println(jedis.setnx("key1", "value1"));
        System.out.println(jedis.setnx("key2", "value2"));
        System.out.println(jedis.setnx("key2", "value2-new"));
        System.out.println(jedis.get("key1"));
        System.out.println(jedis.get("key2"));

        System.out.println("===========新增键值对并设置有效时间=============");
        System.out.println(jedis.setex("key3", 2, "value3"));
        System.out.println(jedis.get("key3"));
        TimeUnit.SECONDS.sleep(3);
        System.out.println(jedis.get("key3"));

        System.out.println("===========获取原值,更新为新值==========");//GETSET is an atomic set this value and return the old value command.
        System.out.println(jedis.getSet("key2", "key2GetSet"));
        System.out.println(jedis.get("key2"));

        System.out.println("获得key2的值的字串:" + jedis.getrange("key2", 2, 4));


    }

    /***
     * 整数和浮点数
     */
    @Test
    public void testNumber() {
        jedis.flushDB();
        jedis.set("key1", "1");
        jedis.set("key2", "2");
        jedis.set("key3", "2.3");
        System.out.println("key1的值:" + jedis.get("key1"));
        System.out.println("key2的值:" + jedis.get("key2"));
        System.out.println("key1的值加1:" + jedis.incr("key1"));
        System.out.println("获取key1的值:" + jedis.get("key1"));
        System.out.println("key2的值减1:" + jedis.decr("key2"));
        System.out.println("获取key2的值:" + jedis.get("key2"));
        System.out.println("将key1的值加上整数5:" + jedis.incrBy("key1", 5));
        System.out.println("获取key1的值:" + jedis.get("key1"));
        System.out.println("将key2的值减去整数5:" + jedis.decrBy("key2", 5));
        System.out.println("获取key2的值:" + jedis.get("key2"));
    }
}

3.3 列表(List)

单键多值

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

号命令及描述1[BLPOP key1 key2 ] timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。2[BRPOP key1 key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。3BRPOPLPUSH source destination timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。4LINDEX key index 通过索引获取列表中的元素5LINSERT key BEFORE|AFTER pivot value 在列表的元素前或者后插入元素6LLEN key 获取列表长度7LPOP key 移出并获取列表的第一个元素8[LPUSH key value1 value2] 将一个或多个值插入到列表头部9LPUSHX key value 将一个值插入到已存在的列表头部10LRANGE key start stop 获取列表指定范围内的元素11LREM key count value 移除列表元素12LSET key index value 通过索引设置列表元素的值13LTRIM key start stop 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。14RPOP key 移除列表的最后一个元素,返回值为移除的元素。15RPOPLPUSH source destination 移除列表的最后一个元素,并将该元素添加到另一个列表并返回16[RPUSH key value1 value2] 在列表中添加一个或多个值17RPUSHX key value 为已存在的列表添加值

它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

image-20211207121044309

lpush/rpush      .... 从左边/右边插入一个或多个值。
lpop/rpop  从左边/右边吐出一个值。值在键在,值光键亡。

rpop lpush  从列表右边吐出一个值,插到列表左边。

lrange   
按照索引下标获得元素(从左到右)
lrange mylist 0 -1   0左边第一个,-1右边第一个,(0-1表示获取所有)
lindex 按照索引下标获得元素(从左到右)
lindex num -1 获取最后一个,就是右边的第一个
lindex num 0
lindex num 6

llen  获得列表长度 

linsert   before 在的后面插入插入值
127.0.0.1:6379> linsert num before 10 1000

lrem   从左边删除n个value(从左到右)
lset   将列表key下标为index的值替换成value

LTRIM key start stop
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。


List的数据结构为快速链表quickList。

首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。

它将所有的元素紧挨着一起存储,分配的是一块连续的内存。

当数据量比较多的时候才会改成quicklist。

因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。

image-20211207121202594

Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

@Test
public void testlist(){
    jedis.flushDB();
    System.out.println("===========添加一个list===========");
    jedis.lpush("collections", "ArrayList", "Vector", "Stack", "HashMap", "WeakHashMap", "LinkedHashMap");
    jedis.lpush("collections", "HashSet");
    jedis.lpush("collections", "TreeSet");
    jedis.lpush("collections", "TreeMap");
    System.out.println("collections的内容:" + jedis.lrange("collections", 0, -1));//-1代表倒数第一个元素,-2代表倒数第二个元素
    System.out.println("collections区间0-3的元素:" + jedis.lrange("collections", 0, 3));
    System.out.println("===============================");
    // 删除列表指定的值 ,第二个参数为删除的个数(有重复时),后add进去的值先被删,类似于出栈
    System.out.println("删除指定元素个数:" + jedis.lrem("collections", 2, "HashMap"));
    System.out.println("collections的内容:" + jedis.lrange("collections", 0, -1));
    System.out.println("删除下表0-3区间之外的元素:" + jedis.ltrim("collections", 0, 3));
    System.out.println("collections的内容:" + jedis.lrange("collections", 0, -1));
    System.out.println("collections列表出栈(左端):" + jedis.lpop("collections"));
    System.out.println("collections的内容:" + jedis.lrange("collections", 0, -1));
    System.out.println("collections添加元素,从列表右端,与lpush相对应:" + jedis.rpush("collections", "EnumMap"));
    System.out.println("collections的内容:" + jedis.lrange("collections", 0, -1));
    System.out.println("collections列表出栈(右端):" + jedis.rpop("collections"));
    System.out.println("collections的内容:" + jedis.lrange("collections", 0, -1));
    System.out.println("修改collections指定下标1的内容:" + jedis.lset("collections", 1, "LinkedArrayList"));
    System.out.println("collections的内容:" + jedis.lrange("collections", 0, -1));
    System.out.println("===============================");
    System.out.println("collections的长度:" + jedis.llen("collections"));
    System.out.println("获取collections下标为2的元素:" + jedis.lindex("collections", 2));
    System.out.println("===============================");
    jedis.lpush("sortedList", "3", "6", "2", "0", "7", "4");
    System.out.println("sortedList排序前:" + jedis.lrange("sortedList", 0, -1));
    System.out.println(jedis.sort("sortedList"));
    System.out.println("sortedList排序后:" + jedis.lrange("sortedList", 0, -1));


    jedis.flushDB();
    jedis.lpush("num","10","20","30","40");
    jedis.lpush("num","1","600");
    jedis.rpush("num","20","11");
    //System.out.println(jedis.lrange("num",0,-1));
    List list =  jedis.lrange("num",0,-1);

    List num = list.stream().map(Integer::parseInt).collect(Collectors.toList());
    System.out.println(num);
    num.sort(Comparator.comparingInt(a -> a));//升序
    System.out.println(num);
    num.sort((a,b)->b-a);//降序
    System.out.println(num);
    Collections.shuffle(num);//乱序
    System.out.println(num);

    System.out.println("--------");
    System.out.println(jedis.sort("num"));
}
3.4 集合(Set)

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

Redis的Set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是****O(1)。

一个算法,随着数据的增加,执行时间的长短,如果是O(1),数据增加,查找数据的时间不变

序号命令及描述1[SADD key member1 member2] 向集合添加一个或多个成员2SCARD key 获取集合的成员数3[SDIFF key1 key2] 返回第一个集合与其他集合之间的差异。4[SDIFFSTORE destination key1 key2] 返回给定所有集合的差集并存储在 destination 中5[SINTER key1 key2] 返回给定所有集合的交集6[SINTERSTORE destination key1 key2] 返回给定所有集合的交集并存储在 destination 中7SISMEMBER key member 判断 member 元素是否是集合 key 的成员8SMEMBERS key 返回集合中的所有成员9SMOVE source destination member 将 member 元素从 source 集合移动到 destination 集合10SPOP key 移除并返回集合中的一个随机元素11[SRANDMEMBER key count] 返回集合中一个或多个随机数12[SREM key member1 member2] 移除集合中一个或多个成员13[SUNION key1 key2] 返回所有给定集合的并集14[SUNIONSTORE destination key1 key2] 所有给定集合的并集存储在 destination 集合中15[SSCAN key cursor MATCH pattern] [COUNT count] 迭代集合中的元素
sadd  ..... 
将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略
smembers 取出该集合的所有值。
127.0.0.1:6379> sadd lang java javascript php html mysql redis spring
(integer) 7
127.0.0.1:6379> type lang
set
127.0.0.1:6379> smembers lang
1) "java"
2) "javascript"
3) "redis"
4) "mysql"
5) "php"
6) "html"
7) "spring"
127.0.0.1:6379> 
sismember 判断集合是否为含有该值,有1,没有0
127.0.0.1:6379> sismember lang mybatis
(integer) 0
127.0.0.1:6379> sismember lang java
(integer) 1

scard返回该集合的元素个数。
srem  .... 删除集合中的某个元素。
spop 随机从该集合中吐出一个值。
127.0.0.1:6379> scard lang
(integer) 7
127.0.0.1:6379> smembers lang
1) "java"
2) "javascript"
3) "redis"
4) "mysql"
5) "php"
6) "html"
7) "spring"
127.0.0.1:6379> srem lang php mysql spring
(integer) 3
127.0.0.1:6379> smembers lang
1) "java"
2) "javascript"
3) "redis"
4) "html"
127.0.0.1:6379> spop lang
"java"
127.0.0.1:6379> spop lang
"redis"
127.0.0.1:6379> spop lang 2
1) "javascript"
2) "html"

srandmember 随机从该集合中取出n个值。不会从集合中删除 。
127.0.0.1:6379> srandmember lang 2
1) "mysql"
2) "java"
127.0.0.1:6379> smembers lang
1) "java"
2) "javascript"
3) "mysql"
4) "html"

smove value把集合中一个值从一个集合移动到另一个集合
127.0.0.1:6379> sadd s1 a b c
(integer) 3
127.0.0.1:6379> sadd s2 10 20 30
(integer) 3
127.0.0.1:6379> smove s1 s2 a
(integer) 1
127.0.0.1:6379> smembers s1
1) "c"
2) "b"
127.0.0.1:6379> smembers s2
1) "30"
2) "a"
3) "20"
4) "10"

sinter 返回两个集合的交集元素。
sunion 返回两个集合的并集元素。
sdiff 返回两个集合的差集元素(key1中的,不包含key2中的)
127.0.0.1:6379> sadd s1 1 2 3 a b c 
(integer) 6
127.0.0.1:6379> sadd s2 1 3 c d b a
(integer) 6
127.0.0.1:6379> sinter s1 s2
1) "a"
2) "3"
3) "1"
4) "b"
5) "c"
127.0.0.1:6379> sdiff s1 s2
1) "2"
127.0.0.1:6379> sunion s1 s2
1) "a"
2) "b"
3) "d"
4) "3"
5) "2"
6) "c"
7) "1"
127.0.0.1:6379> 

Set数据结构是dict字典,字典是用哈希表实现的。

Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。

pom.xml


    org.springframework.data
    spring-data-redis
    2.6.0


    org.apache.commons
    commons-pool2
    2.11.1

 

    redis.clients
    jedis
    3.7.1

RedisConfig.java

@Configuration
public class RedisConfig {
    @Bean(destroyMethod = "close")
    public Jedis jedis(){
        Jedis j = new Jedis("localhost",6379);
        return j;
    }

    @Bean
    public GenericObjectPoolConfig poolConfig(){
        GenericObjectPoolConfig cfg = new GenericObjectPoolConfig();
        return cfg;
    }

    @Bean(destroyMethod = "close")
    public JedisPool jedisPool(){
        JedisPool jp = new JedisPool(poolConfig(), "localhost", 6379, 10000, "123456");
        return jp;
    }
}

SpringDemo.java

@SpringJUnitConfig(RedisConfig.class)
public class SpringDemo {
    @Autowired
    private ApplicationContext ctx;

    @Autowired
    private Jedis jedis;

    @Autowired
    private JedisPool jedisPool;

    /***
     * set集合
     */
    @Test
    public void testSet() {
        jedis.auth("123456");
        jedis.flushDB();
        System.out.println("============向集合中添加元素============");
        System.out.println(jedis.sadd("eleSet", "e1", "e2", "e4", "e3", "e0", "e8", "e7", "e5"));
        System.out.println(jedis.sadd("eleSet", "e6"));
        System.out.println(jedis.sadd("eleSet", "e6"));
        System.out.println("eleSet的所有元素为:" + jedis.smembers("eleSet"));
        System.out.println("删除一个元素e0:" + jedis.srem("eleSet", "e0"));
        System.out.println("eleSet的所有元素为:" + jedis.smembers("eleSet"));
        System.out.println("删除两个元素e7和e6:" + jedis.srem("eleSet", "e7", "e6"));
        System.out.println("eleSet的所有元素为:" + jedis.smembers("eleSet"));
        System.out.println("随机的移除集合中的一个元素:" + jedis.spop("eleSet"));
        System.out.println("随机的移除集合中的一个元素:" + jedis.spop("eleSet"));
        System.out.println("eleSet的所有元素为:" + jedis.smembers("eleSet"));
        System.out.println("eleSet中包含元素的个数:" + jedis.scard("eleSet"));
        System.out.println("e3是否在eleSet中:" + jedis.sismember("eleSet", "e3"));
        System.out.println("e1是否在eleSet中:" + jedis.sismember("eleSet", "e1"));
        System.out.println("e1是否在eleSet中:" + jedis.sismember("eleSet", "e5"));
        System.out.println("=================================");
        System.out.println(jedis.sadd("eleSet1", "e1", "e2", "e4", "e3", "e0", "e8", "e7", "e5"));
        System.out.println(jedis.sadd("eleSet2", "e1", "e2", "e4", "e3", "e0", "e8"));
        System.out.println("将eleSet1中删除e1并存入eleSet3中:" + jedis.smove("eleSet1", "eleSet3", "e1"));
        System.out.println("将eleSet1中删除e2并存入eleSet3中:" + jedis.smove("eleSet1", "eleSet3", "e2"));
        System.out.println("eleSet1中的元素:" + jedis.smembers("eleSet1"));
        System.out.println("eleSet3中的元素:" + jedis.smembers("eleSet3"));
        System.out.println("============集合运算=================");
        System.out.println("eleSet1中的元素:" + jedis.smembers("eleSet1"));
        System.out.println("eleSet2中的元素:" + jedis.smembers("eleSet2"));
        System.out.println("eleSet1和eleSet2的交集:" + jedis.sinter("eleSet1", "eleSet2"));
        System.out.println("eleSet1和eleSet2的并集:" + jedis.sunion("eleSet1", "eleSet2"));
        System.out.println("eleSet1和eleSet2的差集:" + jedis.sdiff("eleSet1", "eleSet2"));//eleSet1中有,eleSet2中没有
    }

    @Test
    public void t2(){
        Jedis js = jedisPool.getResource();
        System.out.println(js.ping());
        //js.sadd("lang","java","javascript","php","html","mysql","中文编程");
        //js.expire("lang",1800l);

        System.out.println(js.smembers("lang"));

    }


    @Test
    public void t1(){
        //显示所有ioc中的bean名称
        System.out.println(Arrays.toString(ctx.getBeanDefinitionNames()));

        System.out.println("hello world");
        jedis.auth("123456");
        System.out.println(jedis.ping());
    }
}

3.5 哈希(Hash)

Redis hash 是一个键值对集合。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

类似Java里面的Map

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储

主要有以下2种存储方式:

image-20211207121742103

序号命令及描述1[HDEL key field1 field2] 删除一个或多个哈希表字段2HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。3HGET key field 获取存储在哈希表中指定字段的值。4HGETALL key 获取在哈希表中指定 key 的所有字段和值5HINCRBY key field increment 为哈希表 key 中的指定字段的整数值加上增量 increment 。6HINCRBYFLOAT key field increment 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。7HKEYS key 获取所有哈希表中的字段8HLEN key 获取哈希表中字段的数量9[HMGET key field1 field2] 获取所有给定字段的值10[HMSET key field1 value1 field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。11HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。12HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。13HVALS key 获取哈希表中所有值。14[HSCAN key cursor MATCH pattern] [COUNT count] 迭代哈希表中的键值对。
hset 给集合中的  键赋值
hget 从集合取出 value 
hmset ... 批量设置hash的值
hexists查看哈希表 key 中,给定域 field 是否存在。 
hkeys 列出该hash集合的所有field
hvals 列出该hash集合的所有value
192.168.16.9:6379> hset user id 100 name lisi 
(integer) 2
192.168.16.9:6379> hmset stu id 11 name wangwu gender nan address zhengzhou
OK
192.168.16.9:6379> type stu
hash
192.168.16.9:6379> type user
hash
192.168.16.9:6379> hget user name
"lisi"
192.168.16.9:6379> hmget stu name address
1) "wangwu"
2) "zhengzhou"
192.168.16.9:6379> hkeys stu
1) "id"
2) "name"
3) "gender"
4) "address"
192.168.16.9:6379> hvals stu
1) "11"
2) "wangwu"
3) "nan"
4) "zhengzhou"
192.168.16.9:6379> hexists user address
(integer) 0
192.168.16.9:6379> hexists stu address
(integer) 1
192.168.16.9:6379> 

hincrby 为哈希表 key 中的域 field 的值加上增量 1   -1
hsetnx 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在 .

Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

@Controller
public class IndexController {
    @Autowired
    private RedisTemplate redisTemplate;
    @RequestMapping
    public String index(Model m){
        //redis string
        var v = redisTemplate.opsForValue();
        v.set("name","张三丰");
        m.addAttribute("msg","中文信息:" + v.get("name"));

        User u = new User();
        u.setId(10);
        u.setName("张三丰");
        u.setMoney(25.5);
        u.setBirth(LocalDate.now());
        u.setRegtime(new Date());
        u.setLtime(LocalDateTime.now());
        u.setLogtime(LocalTime.now());
        Set set = new HashSet();
        set.add("java");
        set.add("java1");
        set.add("java2");
        set.add("java3");
        u.setAddress(set);

        v.set("users",u);

        //redis list
        var list = redisTemplate.opsForList();
        List lt = new ArrayList();
        lt.addAll(List.of("java程序","html网页","mysql数据库"));
        list.leftPushAll("lang",lt);

        //redis set
        var s = redisTemplate.opsForSet();
        s.add("address","郑州","天津","北京","上海");

        //redis hash
        var h = redisTemplate.opsForHash();
        Map map = new HashMap();
        map.put("id",30);
        map.put("name","李四四");
        map.put("birth", LocalDate.now());
        h.putAll("user",map);

        return "index";
    }

    @GetMapping("/show")
    public String show(Model m){
        var list = redisTemplate.opsForList();
        List li = list.range("lang",0,-1);
        m.addAttribute("li",li);
        return "show";
    }
}

3.6 有序集合Zset(sorted set)

Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。

不同之处是有序集合的每个成员都关联了一个评分score,这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。

因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。

访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。

序号命令及描述1[ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成 员的分数2ZCARD key 获取有序集合的成员数192.168.16.9:6379> zcard lang(integer) 53ZCOUNT key min max 计算在有序集合中指定区间分数的成员数192.168.16.9:6379> zcount lang 1 50(integer) 44ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment5[ZINTERSTORE destination numkeys key key …] 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 destination 中6ZLEXCOUNT key min max 在有序集合中计算指定字典区间内成员数量7[ZRANGE key start stop WITHSCORES] 通过索引区间返回有序集合指定区间内的成员8[ZRANGEBYLEX key min max LIMIT offset count] 通过字典区间返回有序集合的成员9[ZRANGEBYSCORE key min max WITHSCORES] [LIMIT] 通过分数返回有序集合指定区间内的成员10ZRANK key member 返回有序集合中指定成员的索引11[ZREM key member member …] 移除有序集合中的一个或多个成员12ZREMRANGEBYLEX key min max 移除有序集合中给定的字典区间的所有成员13ZREMRANGEBYRANK key start stop 移除有序集合中给定的排名区间的所有成员14ZREMRANGEBYSCORE key min max 移除有序集合中给定的分数区间的所有成员15[ZREVRANGE key start stop WITHSCORES] 返回有序集中指定区间内的成员,通过索引,分数从高到低16[ZREVRANGEBYSCORE key max min WITHSCORES] 返回有序集中指定分数区间内的成员,分数从高到低排序17ZREVRANK key member 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序18ZSCORE key member 返回有序集中,成员的分数值19[ZUNIONSTORE destination numkeys key key …] 计算给定的一个或多个有序集的并集,并存储在新的 key 中20[ZSCAN key cursor MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成员和元素分值)
zadd  …
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
192.168.16.9:6379> zadd lang 10 java 5 html
(integer) 2
192.168.16.9:6379> type lang
zset

zrange   [WITHSCORES]   
返回有序集 key 中,下标在之间的元素
带WITHSCORES,可以让分数一起和值返回到结果集。
192.168.16.9:6379> zrange lang 0 1
1) "html"
2) "java"
192.168.16.9:6379> zrange lang 0 1 withscores
1) "html"
2) "5"
3) "java"
4) "10"
192.168.16.9:6379> 

192.168.16.9:6379> zadd lang 100 c 50 javascript 15 mysql
(integer) 3
192.168.16.9:6379> type lang
zset

192.168.16.9:6379> zrange lang 0 8
1) "html"
2) "java"
3) "mysql"
4) "javascript"
5) "c"
192.168.16.9:6379> zrange lang 0 -1  #显示所有元素
1) "html"
2) "java"
3) "mysql"
4) "javascript"
5) "c"
192.168.16.9:6379> 

zrangebyscore key minmax [withscores] [limit offset count]
返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。 
192.168.16.9:6379> zrangebyscore lang 1 50 withscores
1) "html"
2) "5"
3) "java"
4) "10"
5) "mysql"
6) "15"
7) "javascript"
8) "50"


zrevrangebyscore key maxmin [withscores] [limit offset count]               
同上,改为从大到小排列。   withscores 是显示score limit 0 2 分页 第一页

4) "15"
192.168.16.9:6379> zrangebyscore lang 1 50 withscores limit 1 1
1) "java"
2) "10"
192.168.16.9:6379> zrangebyscore lang 1 50 withscores limit 2 1
1) "mysql"
2) "15"
192.168.16.9:6379> zrangebyscore lang 1 200 
1) "html"
2) "java"
3) "mysql"
4) "javascript"
5) "c"
192.168.16.9:6379> zrangebyscore lang 1 200 limit 0 2
1) "html"
2) "java"
192.168.16.9:6379> zrangebyscore lang 1 200 limit 2 2
1) "mysql"
2) "javascript"
192.168.16.9:6379> zrangebyscore lang 1 200 limit 3 2
1) "javascript"
2) "c"
192.168.16.9:6379> zrangebyscore lang 1 200 limit 4 2
1) "c"
192.168.16.9:6379> 

zincrby       为元素的score加上增量
192.168.16.9:6379> zrange lang 0 -1 withscores
 1) "html"
 2) "5"
 3) "java"
 4) "10"
 5) "mysql"
 6) "15"
 7) "javascript"
 8) "50"
 9) "c"
10) "100"
192.168.16.9:6379> zincrby lang 20 html
"25"
192.168.16.9:6379> zrange lang 0 -1 withscores
 1) "java"
 2) "10"
 3) "mysql"
 4) "15"
 5) "html"
 6) "25"
 7) "javascript"
 8) "50"
 9) "c"
10) "100"
192.168.16.9:6379> 
zrem  删除该集合下,指定值的元素 
zcount 统计该集合,分数区间内的元素个数 
192.168.16.9:6379> zcount lang 0 -1
(integer) 0
192.168.16.9:6379> zcount lang 50 100
(integer) 2
192.168.16.9:6379> zrange lang 0 -1
1) "java"
2) "mysql"
3) "html"
4) "javascript"
5) "c"
192.168.16.9:6379> zrem lang javascript c html
(integer) 3
192.168.16.9:6379> zcard lang
(integer) 2
192.168.16.9:6379> zrange lang 0 -1
1) "java"
2) "mysql"
192.168.16.9:6379> 



zrank 返回该值在集合中的排名,从0开始。
192.168.16.9:6379> zrank lang java
(integer) 0
192.168.16.9:6379> zrank lang html
(integer) 2

192.168.16.9:6379> zrange lang 0 -1
1) "java"
2) "mysql"
3) "html"
4) "javascript"
5) "c"
192.168.16.9:6379> zrange lang 0 -1 withscores
 1) "java"
 2) "10"
 3) "mysql"
 4) "15"
 5) "html"
 6) "25"
 7) "javascript"
 8) "50"
 9) "c"
10) "100"
192.168.16.9:6379> 

案例:如何利用zset实现一个文章访问量的排行榜?

image-20211207121635109

SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。

zset底层使用了两个数据结构

(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。

(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。

01、建立springboot项目,pom.xml


    org.springframework.boot
    spring-boot-starter-data-redis
    2.6.1

02、编写配置文件resources/application.yml

spring:
  main:
    banner-mode: off
  redis:
    password: 123456
    host: localhost
    database: 0
    port: 6379

logging:
  level:
    root: off

03、编写命令行程序RedisApp.java

@Service
public class RedisApp implements ApplicationRunner {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ApplicationContext context;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //System.out.println(context.getBeanDefinitionNames().length);
        //var v = redisTemplate.opsForValue();
        //v.set("name","张三丰");
        //System.out.println(v.get("name"));
        var zs = redisTemplate.opsForZSet();
        //增加
        zs.add("lang","c",200);
        zs.add("lang","python",8);
        Set s2 = new HashSet();
        s2.add(TypedTuple.of("ruby",20d));
        s2.add(TypedTuple.of("c++",30d));
        s2.add(TypedTuple.of("html",120d));
        zs.add("lang",s2);
        //读取
        Set set = zs.range("lang",0,-1);
        System.out.println(set);

        var ss = zs.rangeWithScores("lang",0,-1);
        ss.forEach(e->{
            System.out.println(e.getValue() + ":" + e.getScore());
        });

    }
}

关注
打赏
1665409997
查看更多评论
立即登录/注册

微信扫码登录

0.0568s