[Redis] 渐进式遍历+使用jedis操作Redis+使用Spring操作Redis
🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(97平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
目录
- 1. 渐进式遍历
- 1.1 概述
- 1.2 常见指令
- 2. 数据库管理
- 3. 在Java程序中控制Redis
- 3.1 为什么可以使用Java支持Redis
- 3.2 配置Windows环境与服务器的连接
- 3.3 在Java中操作Redis
- 3.3.1 准备工作
- 3.3.2 关于String的操作
- 3.3.3 关于List的操作
- 3.3.4 关于Hash的操作
- 3.3.5 关于set的操作
- 3.3.6 关于zset的操作
- 3.4 在Spring中操作Redis
- 3.4.1 准备工作
- 3.4.2 使用String
- 3.4.3 使用List
- 3.4.4 使用hash
- 3.4.5 使用set
- 3.4.6 使用zset
1. 渐进式遍历
1.1 概述
我们在之前学习过一个指令,叫做keys *,这个指令就是把Redis中所有的key采用遍历的方式全部都获取到.但是这个操作比较危险,可能在Redis中存储的key比较多,可能会阻塞Redis,影响其他指令的执行.
这时候我们就需要使用Redis中的渐进式遍历指令,scan指令.通过渐进式遍历,既可以获取到所有的key,同时又不会卡死服务器.这个命令,不是把所有的key一次性都拿到,而是每次执行命令,只获取其中的一小部分,如果key比较多的话,就需要多次执行scan命令,进行多次渐进式遍历.
1.2 常见指令
-
scan
scan cursor [MATCH pattern] [COUNT count] [TYPE type]
以渐进式遍历的方式对Redis中所有的键进行遍历.- cusor: 表示的是当前从哪个光标开始遍历.其中光标为0的时候,表示的是从头开始遍历所有的key.但是,光标的概念不可以理解为下标,它不是一个连续递增的整数,他只是一个普通的字符串,在每次遍历之后的返回结果中,都会返回下次遍历开始的光标,这个字符串看上去虽然是整数,但是他是一个字符串且和下标不对应,(如果返回的字符串是0,说明遍历已经完成)可能程序员不理解,但是Redis服务器是可以知道这个光标对应的元素的位置的.
- pattern: 和前面介绍的keys命令是一样的.
- count: 限制每次返回的元素个数,默认是10,但是需要注意的是,这里的count和MySQL中的limit不一样.count只是客户端给Redis服务器的一个建议,具体返回多少个,需要看具体的情况,比如只有9个key,但是count写的是10.这时候只返回9个key.但是limit是精确的,指定返回多少个就是返回多少个.
- type: 指定key对应value的类型,其中包含5个通用类型,5个特殊场景使用的类型.

在遍历的过程中,不会在服务器中保存任何的状态信息.比如保存每次遍历之后的光标位置.此处的遍历是可以随时终止的,不会对服务器产生任何的副作用.
就像我们去吃烧烤,如果有一部分烧烤还没有上来,我们就需要退款,这时候老板就到后厨看了一眼,说已经烤上了,退不了了,再比如我们在遍历Redis服务器中的key的时候,遍历了一半,不想遍历了,但是这时候又取消不了,如果强行退出,这时候服务器就会保存状态,这时候就会对服务造成一定的影响,这时候就相当于服务器保存了客户端的状态.再比如我们去超市买东西,如果我们在结账的时候,发现钱没有带够,后面的东西不想要了,这时候可以不扫后面的商品.这时就像Redis中的渐进式遍历,没有保存之前遍历的状态,可以随时停止.
127.0.0.1:6379> mset k1 val1 k2 val2 k3 val3 k4 val4 k5 val5
OK
127.0.0.1:6379> scan 0 count 3
1) "1"//返回下次开始遍历的光标.
2) 1) "k3"2) "k4"3) "k5"
127.0.0.1:6379> scan 1 count 3
1) "0"
2) 1) "k1"2) "k2"//虽然输入的count是3,但是只遍历了2个.
但是scan也存在一定的缺点.渐进式遍历虽然解决了阻塞的问题,但是如果在遍历的期间键有所变化(增加修改删除),可能会导致重复遍历或者是遗漏.
2. 数据库管理
在我们之前学习MySQL中,有一个非常重要的概念,叫做database.其中一个MySQL服务器中可以有很多个database,一个database中也可以有很多张表.
其实在Redis中,也是有database这样的概念的,只不过不像MySQL那样随意,想创建多少个database就创建多少个.Redis中的database是现成的,用户不可以创建数据库,也不可以删除数据库.

默认Redis为我们提供了16个数据库.编号为0~15,这16个数据库之间是相互隔离的.默认的情况下使用的是0号数据库.
- 我们可以通过
select dbIndex(select+数据库编号)的指令来选择数据库.但是在实际使用中我们很少会关注数据库,一般我们使用0号数据库即可. - 我们可以使用
flushdb清除当前数据库中的所有数据.使用flushall清除Redis服务器中的所有数据.
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> SELECT 0
OK
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> keys *
(empty array)
3. 在Java程序中控制Redis
3.1 为什么可以使用Java支持Redis
这个问题,就相当于问,我们为什么可以编写出一个自定义的Redis客户端.首先我们需要知道,在网络通行中,我们会使用到很多的"协议",其中这些协议都是固定好的,是在系统内核中或者驱动程序中实现的,程序员只可以选择,不可以修改.其中传输层协议常见的包含两种,一种是TCP协议,一种是UDP协议,**其中Redis在传输层TCP协议的基础上,自定义了应用层协议,这个协议就是RESP协议.**作为第三方的Java,想要开发一个Redis的客户端,也就需要知道Redis的应用层协议,Redis的RESP协议是在官网上开源出来的.
3.2 配置Windows环境与服务器的连接
在Java开发中,我们一般使用idea进行开发,也就是我们不可以在Linux操作系统上直接对Java进行开发,我们是高度依赖Windows环境的.这就需要我们把Windows中的Redis客户端连接到Linux云服务器中的Redis服务器中.这样的操作,就需要通过Linux服务器的外网IP和Redis服务器的端口号来访问到.但是光知道外网IP和端口号还是不行的,因为Redis服务器对应的默认6379端口号是被云服务器的防火墙保护起来的.也就是这个端口不可以在外网中访问到.
但是千万不可以在云服务器中的安全组配置中开放6379端口号,因为Redis的6379端口号安全系数非常低.开放在公网上很容易被黑客入侵.
那怎么办呢,此时就需要我们来配置xshell客户端与Java客户端的ssh端口转发,把云服务器上的Redis端口映射到本地的主机上.
什么是ssh呢?
ssh就是一个应用层网络协议,ssh默认走的是云服务器的22端口.其中ssh协议最重要的功能就是支持端口转发,相当于通过22端口来传递其他端口的数据.
在Windows主机上访问云服务器的6379端口号的时候,ssh就会构造一个数据报,把要访问Redis的请求放到ssh数据报中(访问6379端口号).
这个数据就会通过22端口发送给服务器,服务器的ssh服务程序,就可以解析出上述数据报,然后把数据报交给6379端口的程序.
比如我们将Windows主机上的8888端口号使用ssh协议映射到服务器上的6379端口号.

关于这个转发,我们需要在xshell中进行配置,后续就可以把云服务器中的端口当做一个本地的端口使用.
- 在使用的服务器上右击,选择属性,选择隧道.

- 选择添加,设置侦听端口为8888,目标端口6379.

- 确定之后,重新连接云服务器生效

- 在Windows系统中的cmd操作版面上,输入指令
netstat -nao|findstr 8888查看8888端口的连接状态,如果出现一下界面,说明连接正常.

- 配置完成之后,后续我们在Java代码中,就可以直接通过127.0.0.1:8888端口来直接访问到云服务器中的Redis.同时外面的客户端无法访问到云服务器的6379.
3.3 在Java中操作Redis
3.3.1 准备工作
- 引入jedis依赖
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.2</version>
</dependency>
- 创建Redis连接,并测试连接
public class Main {public static void main(String[] args) {JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");//redis连接池try (Jedis jedis = jedisPool.getResource()){//获取数据源String ping = jedis.ping();System.out.println(ping);}}
}
返回pong,说明连接成功.

3.3.2 关于String的操作
- get,set.
public class Main {public static void main(String[] args) {JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");//redis连接池try (Jedis jedis = jedisPool.getResource()){//获取数据源stringTest(jedis);}}private static void stringTest(Jedis jedis){jedis.set("key1","value1");//set一次只可以设置一个键值对jedis.set("key2","value2");jedis.set("key3","value3");String key1 = jedis.get("key1");String key2 = jedis.get("key2");String key3 = jedis.get("key100");System.out.println(key1);System.out.println(key2);System.out.println(key3);}
}

- mset,mget
private static void stringTest2(Jedis jedis){jedis.flushAll();jedis.mset("key1","value1","key2","value2","key3","value3");//key和value交替设置List<String> list = jedis.mget("key1","key2","key3");//由于value的值可以重复,所以使用的是list来接收System.out.println(list);
}

在mset的时候,key和value是交替设置的.在mget接收value的时候,由于value的值是可以重复的.所以我们使用List来接收.
- exists,del
private static void stringTest3(Jedis jedis){jedis.flushAll();jedis.set("key1","value1");Boolean ret = jedis.exists("key1");//返回Boolean,即该key是否存在System.out.println(ret);Long ret1 = jedis.del("key1");//返回的是Long类型,即删除成功的个数System.out.println(ret1);
}
exists返回的是Boolean,即该key是否存在,del返回的是Long类型,即删除成功的个数.
- keys
private static void stringTest4(Jedis jedis){jedis.flushAll();jedis.set("key1","value1");jedis.set("key2","value2");jedis.set("key3","value3");jedis.set("key4","value4");jedis.set("key100","value100");Set<String> keys = jedis.keys("*");//由于key不可以重复,所以我们使用set来接收System.out.println(keys);Set<String> keys1 = jedis.keys("key?");//?只匹配一个字符System.out.println(keys1);Set<String> keys2 = jedis.keys("key*");//*可以匹配多个字符System.out.println(keys2);
}

- expire,ttl
private static void stringTest5(Jedis jedis) throws InterruptedException {jedis.flushAll();jedis.set("key1","value1");jedis.set("key2","value2");jedis.set("key3","value3");jedis.set("key4","value4");jedis.expire("key1",5);Long key1 = jedis.ttl("key1");System.out.println(key1);Thread.sleep(6000);//阻塞6秒boolean ret = jedis.exists("key1");System.out.println(ret);
}

- append
private static void stringTest6(Jedis jedis){jedis.flushAll();jedis.set("key1","value1");jedis.append("key1", "aaa");System.out.println(jedis.get("key1"));
}

- getrange,setrange
getrange获取指定字符串区间的字符,setrange设置指定字符串区间的字符.
private static void stringTest7(Jedis jedis){jedis.flushAll();jedis.set("key1","value1aaaa");System.out.println(jedis.getrange("key1", 0, 4));jedis.setrange("key1",0,"bbbbb");System.out.println(jedis.getrange("key1",0,4));
}

- setnx
如果存在key,则不设置,返回0,不存在,则设置
private static void stringTest8(Jedis jedis){jedis.flushAll();jedis.set("key1","value1");long setnx = jedis.setnx("key1", "value1");System.out.println(setnx);
}

- setex
设置键值对,并设置过期时间
private static void stringTest9(Jedis jedis) throws InterruptedException {jedis.flushAll();jedis.setex("key1",2,"value1");Thread.sleep(3000);String s = jedis.get("key1");System.out.println(s);
}

- incr,decr
给指定的key对应的value+1或-1
private static void stringTest10(Jedis jedis){jedis.flushAll();jedis.set("key1","1");jedis.incr("key1");System.out.println(jedis.get("key1"));jedis.decr("key1");System.out.println(jedis.get("key1"));
}

- incrby,decrby
private static void stringTest11(Jedis jedis){jedis.flushAll();jedis.set("key1","1");jedis.incrBy("key1",2);System.out.println(jedis.get("key1"));jedis.decrBy("key1",2);System.out.println(jedis.get("key1"));
}

3.3.3 关于List的操作
- lpush,lpop
private static void listTest1(Jedis jedis){jedis.flushAll();jedis.lpush("list1","v1","v2","v3");System.out.println(jedis.lpop("list1"));System.out.println(jedis.lpop("list1"));System.out.println(jedis.lpop("list1"));
}

- rpush,rpop
private static void listTest2(Jedis jedis){jedis.flushAll();jedis.rpush("key1","v1","v2","v3");System.out.println(jedis.rpop("key1"));System.out.println(jedis.rpop("key1"));System.out.println(jedis.rpop("key1"));
}

- lrange
查看指定下标区间的元素
private static void listTest3(Jedis jedis){jedis.flushAll();jedis.rpush("key1","v1","v2","v3");System.out.println(jedis.lrange("key1",0,1));//左闭右闭
}

- blpop
private static void listTest4(Jedis jedis){jedis.flushAll();jedis.lpush("key1","v1");System.out.println(jedis.blpop(0, "key1"));System.out.println(jedis.blpop(5, "key1"));
}

brpop和blpop同理,这里不再赘述.
- lindex
获取指定下标的元素
private static void listTest5(Jedis jedis){jedis.flushAll();jedis.lpush("key1","v1","v2","v3");System.out.println(jedis.lindex("key1", 2));
}

- linsert
在指定的元素之前或者之后插入指定元素.
private static void listTest6(Jedis jedis){jedis.flushAll();jedis.lpush("key1","v1","v2");jedis.linsert("key1", ListPosition.BEFORE,"v2","100");System.out.println(jedis.lrange("key1",0,-1));
}

- llen
private static void listTest7(Jedis jedis){jedis.flushAll();jedis.rpush("key1","v1","v2","v3");System.out.println(jedis.llen("key1"));
}

3.3.4 关于Hash的操作
- hset,hget
private static void hashTest1(Jedis jedis){jedis.flushAll();jedis.hset("key1","field1","value1");jedis.hset("key1","field2","value2");jedis.hset("key1","field3","value3");System.out.println(jedis.hget("key1", "field1"));System.out.println(jedis.hget("key1", "field2"));System.out.println(jedis.hget("key1", "field3"));
}

- hexists,hdel
private static void hashTest2(Jedis jedis){jedis.flushAll();jedis.hset("key1","field1","value1");jedis.hset("key1","field2","value2");jedis.hset("key1","field3","value3");System.out.println(jedis.hexists("key1", "field1"));System.out.println(jedis.hexists("key1", "field100"));jedis.hdel("key1","field1");System.out.println(jedis.hgetAll("key1"));
}

- hkeys,hvals
private static void hashTest3(Jedis jedis){jedis.flushAll();jedis.hset("key1","field1","value1");jedis.hset("key1","field2","value2");jedis.hset("key1","field3","value3");System.out.println(jedis.hkeys("key1"));//获取所有的keySystem.out.println(jedis.hvals("key1"));//获取所有的val
}

- hmget
private static void hashTest4(Jedis jedis){jedis.flushAll();jedis.hset("key1","field1","value1");jedis.hset("key1","field2","value2");jedis.hset("key1","field3","value3");System.out.println(jedis.hmget("key1","field1","field2"));
}

- hlen
private static void hashTest5(Jedis jedis){jedis.flushAll();jedis.hset("key1","field1","value1");jedis.hset("key1","field2","value2");jedis.hset("key1","field3","value3");System.out.println(jedis.hlen("key1"));
}

- hincrby,hincrbyfloat
private static void hashTest6(Jedis jedis){jedis.flushAll();jedis.hset("key1","field1","2");jedis.hincrBy("key1","field1",1);System.out.println(jedis.hget("key1","field1"));jedis.hincrByFloat("key1","field1",1.5);System.out.println(jedis.hget("key1","field1"));
}

3.3.5 关于set的操作
- sadd,smember
private static void setTest1(Jedis jedis){jedis.flushAll();jedis.sadd("key1","m1","m2","m3");jedis.sadd("key1","m1");System.out.println(jedis.smembers("key1"));
}

- srem,sismember
private static void setTest2(Jedis jedis){jedis.flushAll();jedis.sadd("key1","m1","m2","m3");System.out.println(jedis.smembers("key1"));jedis.srem("key1","m1");System.out.println(jedis.smembers("key1"));System.out.println(jedis.sismember("key1", "m1"));System.out.println(jedis.sismember("key1", "m2"));
}

- scard
private static void setTest3(Jedis jedis){jedis.flushAll();jedis.sadd("key1","m1","m2","m3");System.out.println(jedis.scard("key1"));
}

- sinter
private static void setTest4(Jedis jedis){jedis.flushAll();jedis.sadd("key1","m1","m2","m3");jedis.sadd("key2","m2","m3","m4");System.out.println(jedis.sinter("key1","key2"));
}

sunion和sdiff是同样的道理,这里不再赘述.
3.3.6 关于zset的操作
- zadd,zrange,zrangeWithScores
private static void zsetTest1(Jedis jedis){jedis.flushAll();jedis.zadd("key1",90,"zhangfei");jedis.zadd("key1",91,"zhaoyun");jedis.zadd("key1",92,"guanyu");System.out.println(jedis.zrange("key1",0,-1));System.out.println(jedis.zrangeWithScores("key1",0,-1));//返回的是带有分数的二元组
}

- zrem,zcard
private static void zsetTest2(Jedis jedis){jedis.flushAll();jedis.zadd("key1",90,"zhangfei");jedis.zadd("key1",91,"zhaoyun");jedis.zadd("key1",92,"guanyu");jedis.zrem("key1","guanyu");System.out.println(jedis.zcard("key1"));System.out.println(jedis.zrangeWithScores("key1",0,-1));
}

- zcount
返回指定分数区间的所有key
private static void zsetTest3(Jedis jedis){jedis.flushAll();jedis.zadd("key1",90,"zhangfei");jedis.zadd("key1",91,"zhaoyun");jedis.zadd("key1",92,"guanyu");System.out.println(jedis.zcount("key1",90,91));
}

- zpopmax,zpopmin
private static void zsetTest4(Jedis jedis){jedis.flushAll();jedis.zadd("key1",90,"zhangfei");jedis.zadd("key1",91,"zhaoyun");jedis.zadd("key1",92,"guanyu");System.out.println(jedis.zpopmax("key1"));System.out.println(jedis.zpopmin("key1"));
}

- zrank
按升序的顺序返回指定元素的排名
private static void zsetTest5(Jedis jedis){jedis.flushAll();jedis.zadd("key1",90,"zhangfei");jedis.zadd("key1",91,"zhaoyun");jedis.zadd("key1",92,"guanyu");System.out.println(jedis.zrank("key1","guanyu"));
}

- zscore
获取指定元素的分数.
private static void zsetTest6(Jedis jedis){jedis.flushAll();jedis.zadd("key1",90,"zhangfei");jedis.zadd("key1",91,"zhaoyun");jedis.zadd("key1",92,"guanyu");System.out.println(jedis.zscore("key1","zhaoyun"));
}

- zincrby
给指定的元素加上指定的分数
private static void zsetTest7(Jedis jedis){jedis.flushAll();jedis.zadd("key1",90,"zhangfei");jedis.zadd("key1",91,"zhaoyun");jedis.zadd("key1",92,"guanyu");jedis.zincrby("key1",10,"zhaoyun");System.out.println(jedis.zscore("key1","zhaoyun"));
}

- zinterstore
private static void zsetTest8(Jedis jedis){jedis.flushAll();jedis.zadd("key1",90,"zhangfei");jedis.zadd("key1",91,"zhaoyun");jedis.zadd("key1",92,"guanyu");jedis.zadd("key2",90,"zhangfei");jedis.zadd("key2",91,"zhaoyun");jedis.zadd("key2",93,"zhugeliang");jedis.zinterstore("key3","key1","key2");System.out.println(jedis.zrangeWithScores("key3",0, -1));
}

union和diff是同样的道理,这里不再赘述.
3.4 在Spring中操作Redis
3.4.1 准备工作
首先,我们需要创建一个Spring项目,在创建项目的时候,我们需要引入"Spring Data Redis"和"Spring Web"依赖.

之后我们需要配置Redis的主机与端口号.在yml配置文件中配置一下内容:
spring:redis:host: 127.0.0.1port: 8888
之后我们需要在Controller中注入StringRedisTemplate对象
@RequestMapping("/redis")
@RestController
public class SpringRedis {@Autowiredpublic StringRedisTemplate redisTemplate;//注入StringRedisTemplate实例
}
后续我们在操作的时候,就像jedis中共使用jedis对象一样,都用的是注入的redisTemplate对象.
3.4.2 使用String
对于Spring中对Redis的操作,我们不再展示全部方法,有些方法是我们一看就知道什么意思的,学习成本较低,所以我们只展示一部分的方法.
@RequestMapping("/test1")
public String stringTest1(){redisTemplate.opsForValue().set("key1","value1");return redisTemplate.opsForValue().get("key1");
}

这里我们需要注意的是,Spring中的操作和jedis中的操作有些不一样的地方,我们在Spring中操作的时候,需要提前指定操作value的类型,比如我们上面使用opsForValue()指定的就是value为String类型的数据.
我们还需要注意一下几点:
- 在我们不知道Spring中的什么方法对应Redis中的方法,我们可以使用lambda表达式的方法来为
execute()方法传递我们所要在Redis中所做的事情,在lambda表达式中,使用RedisConnection参数的时候,就可以使用我们熟悉的api来操作Redis了,在lambda表达式中操作Redis的方法与我们前面学习jedis的方法大相径庭.
比如我们在执行一个Controller方法之前,我们需要清空数据库:
redisTemplate.execute((RedisConnection connection)->{connection.flushAll();return null;
});
- 在使用Spring操作数据库的时候,在我们删除其中的键值对的时候,不需要指定操作的数据类型:
@RequestMapping("/test2")
public String stringTest2(){redisTemplate.execute((RedisConnection connection)->{connection.flushAll();return null;});redisTemplate.opsForValue().set("key1","value1");System.out.println(redisTemplate.opsForValue().get("key1"));System.out.println(redisTemplate.delete("key1"));return "ok";
}

3.4.3 使用List
这里的opsForList()就相当于Redis原生指令操作中开头的l一样,就是首先声明是要对一个List进行操作.
@RequestMapping("/test3")
public String listTest1(){redisTemplate.opsForList().rightPushAll("key1","value1","value2");System.out.println(redisTemplate.opsForList().range("key1", 0, -1));System.out.println(redisTemplate.opsForList().leftPop("key1"));System.out.println(redisTemplate.opsForList().leftPop("key1"));System.out.println(redisTemplate.opsForList().leftPop("key1"));redisTemplate.delete("key1");return "ok";
}

3.4.4 使用hash
@RequestMapping("/test4")
public String hashTest1(){redisTemplate.opsForHash().put("key1","field1","value1");redisTemplate.opsForHash().put("key1","field2","value2");redisTemplate.opsForHash().put("key1","field3","value3");System.out.println(redisTemplate.opsForHash().get("key1","field1"));redisTemplate.opsForHash().delete("key1","field1");System.out.println(redisTemplate.opsForHash().keys("key1"));System.out.println(redisTemplate.opsForHash().values("key1"));redisTemplate.delete("key1");return "ok";
}

3.4.5 使用set
@RequestMapping("/test5")
public String setTest(){redisTemplate.opsForSet().add("key1","value1","value2","value3");System.out.println(redisTemplate.opsForSet().isMember("key1", "value1"));//判断其中是否存在指定元素System.out.println(redisTemplate.opsForSet().remove("key1", "value2"));//删除指定元素System.out.println(redisTemplate.opsForSet().pop("key1"));//随机弹出一个元素System.out.println(redisTemplate.opsForSet().size("key1"));redisTemplate.delete("key1");return "ok";
}

3.4.6 使用zset
@RequestMapping("/test6")
public String zsetTest(){redisTemplate.delete("key1");redisTemplate.opsForZSet().add("key1","zhaoyun",90.0);redisTemplate.opsForZSet().add("key1","guanyu",91.0);redisTemplate.opsForZSet().add("key1","zhugeliang",92.0);System.out.println(redisTemplate.opsForZSet().range("key1", 0, -1));//返回指定区间的成员和分数System.out.println(redisTemplate.opsForZSet().count("key1", 90.0, 92.0));//返回指定分数区间的元素个数return "ok";
}

相关文章:
[Redis] 渐进式遍历+使用jedis操作Redis+使用Spring操作Redis
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
排序----数据结构
Comparable Integer Double 默认情况下都是按照升序排列的 string 按照字母再ASCII码表中对应的数字升序进行排列 冒泡排序 时间复杂度O(x^2) 选择排序 时间复杂度O(x^2) 插入排序 时间复杂度O(x^2) 希尔排序 时间复杂度O(x) 归并排序 时间复杂度O(nlogn) 快速排序...
Crack道路裂缝检测数据集——目标检测数据集
【Crack道路裂缝检测数据集】共3684张。 目标检测数据集,标注文件为YOLO适用的txt格式。已划分为训练、验证集。 图片分辨率:224*224 类别:crack Crack道路裂缝检测数据集 数据集描述 该数据集是一个专门用于训练和评估基于YOLO࿰…...
10.3拉普拉斯金字塔
实验原理 拉普拉斯金字塔(Laplacian Pyramid)是一种图像表示方法,常被用于图像处理和计算机视觉领域。它是基于高斯金字塔的一种变换形式,主要用于图像融合、图像金字塔的构建等场景。下面简要介绍拉普拉斯金字塔的基本原理。 高…...
redis为什么不使用一致性hash
Redis节点间通信时,心跳包会携带节点的所有槽信息,它能以幂等方式来更新配置。如果采用 16384 个插槽,占空间 2KB (16384/8);如果采用 65536 个插槽,占空间 8KB (65536/8)。 今天我们聊个知识点为什么Redis使用哈希槽而不是一致性…...
Vue.js与Flask/Django后端配合
Vue.js与Flask/Django后端配合 在现代Web开发领域,前后端分离已成为一种流行的架构模式。Vue.js作为一款轻量级、高性能的前端框架,与Flask或Django这样的后端框架相结合,可以构建出强大且可扩展的Web应用。本文将详细介绍如何将Vue.js与Fla…...
ESP32 入门笔记02: ESP32-C3 系列( 芯片ESP32-C3FN4) (ESP-IDF + VSCode)
ESP32-C3 系列的 芯片 / 模组 / 开发板 ESP32-C3-DevKitM-1是乐鑫一款搭载 ESP32-C3-MINI-1 或 ESP32-C3-MINI-1U 模组的入门级开发板(内置 ESP32-C3FH4 或 ESP32-C3FN4 芯片)。 板上模组大部分管脚均已引出至两侧排针,可根据开发实际需求&a…...
Vue主题色实现
主题色实现 情境 配置平台支持多个主题色的选择,用户可通过在配置平台选择项目主题色。前端项目在骨架屏加载页面获取配置信息,设置项目主题色,实现同个项目不同主题色渲染的需求 实现 1.定义主题色变量 不同主题色根据不同js文件划分定…...
ChartLlama: A Multimodal LLM for Chart Understanding and Generation论文阅读
原文链接:https://arxiv.org/abs/2311.16483 代码与数据集:https://tingxueronghua.github.io/ChartLlama/ 本文启发:文章提出利用GPT-4合成大量图表数据,这些数据包含各种图表类型,包含丰富的instruction data。然后…...
ByteCinema(1):用户的登录注册
文章目录 主要功能生成图形验证码redis滑动窗口操作限流0.限流设计的必要性1.原理2.代码(邮箱发验证码为例)3. 问题与解决高并发环境下redis操作的原子性过时数据的积累 续约token实现长期登录0.设计的出发点1.前置知识:JWT什么是 JWT?JWT 的…...
电力电网电线变电站输电线绝缘子无人机类数据集/农业植物病虫害类数据集/光伏板/工程煤矿矿场类数据集/道路类数据集
电力电网电线变电站输电线红外缺陷类数据集 传送门链接: 1.电线覆盖物检测数据集 气球风筝鸟巢 1300张 voc yol-CSDN博客 2.变电站可见光缺陷数据集数据集包含8376张巡检图像,带xml标签,共包含17类巡检标签!具体缺陷分类见下图!…...
深度学习之表示学习 - 引言篇
序言 在数据爆炸的今天,如何从纷繁复杂的信息中抽取有价值的知识,成为了人工智能领域亟待解决的核心问题。深度学习,作为机器学习的一个重要分支,以其强大的特征表示能力和自动化学习特性,引领了这场数据革命的浪潮。…...
Linux驱动开发 ——架构体系
只读存储器(ROM) 1.作用 这是一种非易失性存储器,用于永久存储数据和程序。与随机存取存储器(RAM)不同,ROM中的数据在断电后不会丢失,通常用于存储固件和系统启动程序。它的内容在制造时或通过…...
Django一分钟:lookupAPI详解,使用django orm生成高效的WHERE子句
一、Lookup API概述 Lookup API是Django用于构建数据库查询WHERE子句的API。 Lookup API的核心包含两部分: RegisterLookupMixin:为子类提供注册lookup的方法Query Expression API:一个接口,规定了可以被注册为lookup的类需要实…...
信息安全工程师(8)网络新安全目标与功能
前言 网络新安全目标与功能在当前的互联网环境中显得尤为重要,它们不仅反映了网络安全领域的最新发展趋势,也体现了对网络信息系统保护的不断加强。 一、网络新安全目标 全面防护与动态应对: 目标:建立多层次、全方位的网络安全防…...
返利机器人在电商返利系统中的负载均衡实现
返利机器人在电商返利系统中的负载均衡实现 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来聊一聊如何在电商返利系统中实现返利机器人的负载均衡,尤其是在面对高并发和大量…...
MATLAB中typecast函数用法
目录 语法 说明 示例 将整数转换为相同存储大小的无符号整数 将 8 位整数转换为单精度 将 32 位整数转换为 8 位整数 将 8 位整数转换为 16 位整数 提示 typecast函数的功能是在不更改基础数据的情况下转换数据类型。 语法 Y typecast(X,type) 说明 Y typecast(X,…...
植物大战僵尸【源代码分享+核心思路讲解】
植物大战僵尸已经正式完结,今天和大家分享一下,话不多说,直接上链接!!!(如果大家在运行这个游戏遇到了问题或者bug,那么请私我谢谢) 大家写的时候可以参考一下我的代码思…...
变压器设备漏油数据集 voc txt
变压器设备漏油数据集 油浸式变压器通常采用油浸自冷式、油浸风冷式和强迫油循环三种冷却方式。该数据集采集于油浸式变压器的设备漏油情况,一般用于变电站的无人巡检,代替传统的人工巡检,与绝缘子的破损检测来源于同一课题。数据集一部分来自…...
算法练习题25——leetcode3279统计重新排列后包含另一个字符串的子字符串的数目(滑动窗口 双指针 哈希)
题目描述 解题思路 本题用到了滑动窗口 双指针 哈希 刚开始我是没读懂题的因为我笨 我想把我的思路说一下 左端不轻易缩小 只有找到跟word2匹配了 比如说abbcdd 遍历到c的时候才能匹配这个word2 对吧 那么之后加上以一个d或者俩d 都符合了 然后我们算完了 才能缩小左端 扩大…...
2026届学术党必备的五大AI科研助手横评
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 为学术写作供给高效解决办法的是论文一键生成技术,此工具依据自然语言处理跟深度…...
ILI9341 TFT驱动库:嵌入式HMI全栈图形解决方案
1. 项目概述ILI9341_LTSM 是一款面向 Arduino 生态系统的 C 驱动库,专为 ILI9341 控制芯片的 SPI 接口 TFT LCD 显示屏设计。该库并非仅提供基础初始化与像素写入功能,而是构建了一套完整的嵌入式图形子系统,覆盖从底层硬件抽象、图形绘制、字…...
2026届最火的六大降重复率神器实际效果
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 目前人工智能生成内容大范围运用的情形下,致使 AIGC 检测识别率降低的工具适时出…...
【2026年最新600套毕设项目分享】基于Java的游泳馆管理系统(14337)
有需要的同学,源代码和配套文档领取,加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码(前后端源代码SQL脚本)配套文档(LWPPT开题报告/任务书)远程调试控屏包运行一键启动项目&…...
降AI率工具8元和3元的,处理80%+有区别吗
“8元一千字太贵了,3元那个不是也能用吗?” 这个问题很合理,特别是对于字数多的毕业论文,价格差距相当可观。 4万字的论文: 8元工具:320元3元工具:约130元 差了190元。那这190元换来的是什么…...
基于Vivado工程的FPGA多通道以太网实时同步采集系统——AD7606八通道同步采集与UD...
基于FPGA多通道以太网实时同步采集系统 FPGA: Vivado工程 AD芯片:AD7606 传输协议:UDP 上位机开发软件:QT5.12 AD7606八通道同步采集,最高采样率200KHz,上位机发送指令开始采集,上位机通过千兆以太网udp进行数据传输 QT上位机软件:udp上位…...
番茄小说下载创新工具:一站式EPUB转换与离线阅读解决方案
番茄小说下载创新工具:一站式EPUB转换与离线阅读解决方案 【免费下载链接】Tomato-Novel-Downloader 番茄小说下载器不精简版 项目地址: https://gitcode.com/gh_mirrors/to/Tomato-Novel-Downloader 在数字阅读日益普及的今天,小说爱好者常面临三…...
Qt数据库连接实战:QSqlDatabase从配置到优化的完整指南
Qt数据库连接实战:QSqlDatabase从配置到优化的完整指南 在当今数据驱动的应用开发中,数据库连接作为系统与数据之间的桥梁,其稳定性和性能直接影响着用户体验。对于Qt开发者而言,QSqlDatabase作为连接各类数据库的核心类ÿ…...
2026最权威的五大降AI率方案实测分析
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 在进行 内容创作 时,要降低 AIGC 率,其核心之处在于 削弱 机器生成所…...
永磁同步电机2D电磁仿真模型代码功能说明
Maxwell电机多目标尺寸优化 Ansys Maxwell 和OptiSlang 有案例电机,永磁同步电机内嵌式 满足电机多尺寸参数入手,满足多尺寸联动优化,最终达到多参数优化效果 提供源文件,提供操作视频一、文档概述 本文档基于Ansys Maxwell 2019 …...


