Redis简介 Redis使大规模互联网应用常用的内存高速缓存数据库,它的读写速度非常快。Redis是目前使用最广泛的内存数据存储系统之一。它支持更丰富的数据结构,支持数据持久化、事务、HA(高可用High Available)、双机集群系统、主从库。
Redis是key-value存储系统。它支持的value类型包括String、List、Set、Zset(有序集合)和Hash。这些数据类型都支持push/pop、add/remove,以及取交集、并集、差集或更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序和算法。
Redis会周期性地把更新后的数据写入磁盘,后把修改操作写入追加的记录文件中(RDB和AOF两种方式),并且在此基础上实现了master-slave同步。机器重启后,能通过持久化数据自动重建内存。如果使用Redis作为Cache,则机器宕机后热点数据不会丢失。
Redis为什么快? 纯内存操作;单线程操作,避免了频繁的上下文切换;采用了非阻塞I/O多路复用机制。
高并发的读写:Redis特别适合将方法的运行结果放入缓存,以便后续在请求方法时直接去缓存中读取。对执行耗时,且结果不频繁变动的SQL查询的支持极好。在高并发的情况下,应尽量避免请求直接访问数据库,这时可以使用Redis进行缓冲操作,让请求先访问Redis。
计数器:电商网站商品的浏览量、视频网站上视频的播放数量等数据都会被统计,以便用于运营或产品分析。为了保证数据实时生效,每次浏览量都得+1,这会导致非常高的并发量。这时可以用Redis提供的incr命令来实现计数器功能,这一切在内存中操作,所以性能非常好,非常适用于这些计数场景。
排行榜:可以利用Redis提供的有序集合数据类,实现各种复杂的排行榜应用。如京东、淘宝的销售榜单,商品按时间、销量排行。
分布式会话:在集群模式下,一般都会搭建以Redies等内存数据库为中心的Session服务,它不再有容器管理,而是由Session服务以及内存数据库管理。
互动场景:使用Redis提供的散列、集合等数据结构,可以很方便地实现网站中点赞、踩、关注共同好友等社交场景的基本功能。
最新列表:Redis可以通过LPUSH在列表头部插入一个内容ID作为关键字,LTRIM可用来限制列表的数量,这样列表永远为N个ID,无需查询最新的列表,直接根据ID查找对应的内容即可。
Redis有5种数据类型
数据类型存储的值读写能力string(字符串)可以时字符串、正数或者浮点数对整个字符串或字符串的一部分执行操作;对对象和浮点数执行自增或自减操作list(列表)一个链表,链表上的每个节点都包含了一个字符串从链表的两端推入或弹出元素;根据偏移量对链表进行修剪(prim);读取单个或多个元素;根据值来查找或移除元素set(集合)包含字符串的无序收集器,并且每个字符串各不相同添加、获取、移除单个元素;检查一个元素是否存在于某个集合中;计算交集、并集、差集;从集合里随机获取元素hash(散列)包含键值对的无序散列表添加、获取、移除单个键值对;获取所有键值对zset(有序集合)字符串成员与浮点数分值之间的有序映射,元素的排列顺序由分值的大小决定加、获取、删除单个元素;根据分值范围或成员来获取元素1.字符串 Redis字符串可以包含任意类型的数据、字符、整数、浮点数等。一个字符串类型的值的容量时512MB,代表能存储最大512MB的内容。可以使用INCR(DECR,INCRBY)命令来把字符串当作原子计数器使用。使用APPEND命令在字符串后面添加内容。应用场景:计数器。
2 列表 Redis列表是简单的字符串列表,按照插入顺序排序。可以通过LPUSH,RPUSH命令添加一个元素到列表的头部或尾部。一个列表最多包含 2 32 − 1 2^{32}-1 232−1(约为42.95亿)个元素。应用场景:取最新N个数据的操作,消息队列,删除与过滤,实时分析正在发生的情况,数据统计与防止垃圾邮件。
3 集合 Redis集合是一个无序的、不允许相同成员存在的字符串集合。支持一些服务器端的命令从现有的集合出发去进行集合运算,如合并,求交集、差集,找出不同元素的操作。应用场景:Unique操作,可以获取某段时间内所有数据的去重值,比如用于共同好友、二度好友、统计独立IP、好友推荐等。
4 散列 Redis hash是字符串字段和字符串值之间的映射,主要用来表示对象,也能够存储许多元素。应用场景:存储、读取、修改用户属性。
5 有序集合 Redis有序集合不包含相同字符串,每个有序集合的 成员都关联着一个评分,这个评分用于把有序集合中的成员按最低分到最高分排列。使用有序集合,可以非常快捷地完成添加、删除、更新元素的操作。元素是在插入时就排好序,所以很快地通过评分(Score)或位次(Position)获得一个范围的元素。应用场景:排行榜应用、取TOP N操作,需要精准设定过期时间的应用(时间戳作为Score)、带有权重的元素(游戏用户得分排行榜)、过期项目处理、按照时间排序等。
Spring封装了Redis Template来操作Redis,它支持所有的Redis原生的API。在RedisTemplate中定义了对5种数据结构的操作方法。
opsForValue():操作字符串opsForHash():操作散列opsForList():操作列表opsForSet():操作集合opsForZSet():操作有序集合RedisTemplate提供以下操作String 的方法。 1.set void set(K key,V value);get V get(Object key);
具体使用见下面代码
@Autowired private RedisTemplate redisTemplate; @Test public void string(){ redisTemplate.opsForValue().set("num",123); redisTemplate.opsForValue().set("nihao","I am lsz"); redisTemplate.opsForValue().set("lishizheng","first time using Redis"); Object s=redisTemplate.opsForValue().get("num"); Object s2=redisTemplate.opsForValue().get("nihao"); Object s3=redisTemplate.opsForValue().get("lishizheng"); System.out.println(s); System.out.println(s2); System.out.println(s3); }运行结果
123 I am lsz first time using Redis第一次使用Spring Boot使用redis,报错如下
Unable to connect to 127.0.0.1:6379原因是:自己没有安装Redis也没有启动Redis服务,自然无法连接。安装并启动Redis之后,可以正常连接Redis。另外这个界面需要一直打开以表示redis服务是开启的,可能是还没有配置的原因
2.set void set(K key,V value,long timeout,TimeUnit unit)
TimeUnit是java.util.concurrrent包下面的一个类,表示给定单元粒度的时间段,常用的颗粒度有
天:TimeUnit.DAYS小时:TimeUnit.HOURS分钟:TimeUnit.MINUTES秒:TimeUnit.SECONDS毫秒:TimeUnit.MILLISECONS以下代码设置3s失效。3s之内查询有结果,如果3s之后查询则会返回null。
@Test public void string2(){ //设置的是3s失效 redisTemplate.opsForValue().set("num","dsafadfadaafaa",3, TimeUnit.SECONDS); try { Object s=redisTemplate.opsForValue().get("num"); System.out.println(s); Thread.currentThread().sleep(2000); Object s2=redisTemplate.opsForValue().get("num"); System.out.println(s2); Thread.currentThread().sleep(5000); Object s3=redisTemplate.opsForValue().get("num"); System.out.println(s3); }catch (InterruptedException ie){ ie.printStackTrace(); } }控制台输出结果
dsafadfadaafaa dsafadfadaafaa null3.set void set(K key,V value,long offset)
给定key所存储的字符串值,从偏移量offset开始。具体用法见以下代码
这里遇到问题,报错如下
Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.StreamCorruptedException: invalid stream header: 00000000错误提示:序列号对象生成这个字节数组的方法是否与默认的反序列化方法相对应。 错误代码
@Test @Test public void string3(){ //重写给定key所存储的字符串,从偏移量offset开始 redisTemplate.opsForValue().set("key","hello world"); System.out.println(redisTemplate.opsForValue().get("key")); redisTemplate.opsForValue().set("key","git",6); System.out.println(redisTemplate.opsForValue().get("key")); }原因分析:因为本文的测试只是在test文件夹下写的,main文件夹下面没有东西,看来需要重新开始。这次重新开了一个Spring Boot项目,项目结构如下,在完成了这篇文章之后:SpringBoot使用Redis和MyBatis完成缓存数据的增删改查,顺手在test文件夹下新建controller,添加RedisTypeTest.java用来测试 这次注意了Redis序列化/发序列化的配置 配置Redis类 要想启动Spring缓存支持,需要创建一个CacheManager的Bean。
RedisConfig.java
package com.example.demo.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.lang.reflect.Method; @Configuration public class RedisConfig extends CachingConfigurerSupport{ @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } @SuppressWarnings("rawtypes") @Bean //缓存管理器 public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheManager cacheManager = RedisCacheManager.create(connectionFactory); //设置缓存过期时间 return cacheManager; } @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { //配置连接工厂 StringRedisTemplate template = new StringRedisTemplate(factory); //使用Jackson2JsonRedisSerializer来序列化和反序列化redis 的value值 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); //指定要序列化的域,field,get和set,以及修饰符范围 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //指定序列化输入的类型,类必须是非final类 om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance , ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); jackson2JsonRedisSerializer.setObjectMapper(om); //序列化配置为String格式 template.setValueSerializer(new StringRedisSerializer()); // template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } }关于Redis Template中序列化和反序列化配置的解释 关于数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)
序列化/发序列化解释JdkSerializationRedisSerializerPOJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。StringRedisSerializer适用于Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成stringJacksonJsonRedisSerializer提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。OxmSerializer提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。上面4种策略中:
JdkSerializationRedisSerializer和StringRedisSerializer是最基础的策略,在设计时仍然不推荐直接使用后面两种,即JacksonJsonRedisSerializer和OxmSerializer,因为无论是json还是xml,他们本身仍然是String。
如果数据需要被第三方工具解析,那么数据应该使用StringRedisSerializer而不是JdkSerializationRedisSerializer。
如果数据格式必须为json或者xml,那么在编程级别,在redisTemplate配置中仍然使用StringRedisSerializer,在存储之前或者读取之后,使用“SerializationUtils”工具转换转换成json或者xml
经过一番折腾
@Test public void string3(){ //重写给定key所存储的字符串,从偏移量offset开始 redisTemplate.opsForValue().set("key","hello world"); System.out.println(redisTemplate.opsForValue().get("key")); redisTemplate.opsForValue().set("key","git",6); System.out.println(redisTemplate.opsForValue().get("key")); }结果为
hello world hello gitld可以看到,从偏移量6开始用git字符串覆盖掉原字符串。
4.getAndSet V getAndSet(K key,V value) 设置键的字符串值,并返回其旧值。具体用法如下:
@Test public void string4(){ //设置键的字符串值并返回其旧值 redisTemplate.opsForValue().set("english","C primer plus"); System.out.println(redisTemplate.opsForValue().getAndSet("english","usage")); System.out.println(redisTemplate.opsForValue().get("english")); }返回结果
C primer plus usage5.append Integer append(K key,String value)
如果key已经存在,已经是一个字符串,则该命令将该值追加到字符串的末尾。如果key不存在,则它将被创建并被设置为空字符串。
@Test public void string5() { redisTemplate.opsForValue().set("k", "test"); redisTemplate.opsForValue().append("k","test"); System.out.println(redisTemplate.opsForValue().get("k")); redisTemplate.opsForValue().append("k","forwhat"); System.out.println(redisTemplate.opsForValue().get("k")); }测试结果
testtest testtestforwhat这里曾经遇到过问题Redis Template使用append方法不起作用的解决办法以及序列化/反序列化的解释
6.size Long size(K key)
返回key所对应的value值的长度 使用如下:下面将返回字符串howareu的长度,为7
@Test public void string6() { redisTemplate.opsForValue().set("key","howareu"); System.out.println(redisTemplate.opsForValue().size("key")); }测试结果
7Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。value中存放的是结构化的对象。利用这种数据结构,可以方便地操作其中的某个字段。比如在“点击登录”时,可以用这种数据结构存储用户信息。以CookedId作为key,设置30分钟为缓存过期时间,能很好地模拟出类似Session的效果。
1.void putAll(H key,Map<? extends HK,? extends HV> m)
用m中提供的多个散列字段设置到key对应的散列表中。
举例如下:这里的m是testMap,这里key 是Hash,可以看到结果,而key是hash,由于没有设置因此为空。
@Test public void hash1(){ Map<String,Object> testMap=new HashMap(); testMap.put("name","shizheng"); testMap.put("sex","male"); redisTemplate.opsForHash().putAll("Hash",testMap); System.out.println(redisTemplate.opsForHash().entries("Hash")); System.out.println(redisTemplate.opsForHash().entries("hash")); }测试结果
{sex=male, name=shizheng} {}2.void put(H key,HK hashKey,HV value)
设置hashKey的值
@Test public void hash2() { redisTemplate.opsForHash().put("testName", "name", "shizheng"); redisTemplate.opsForHash().put("testName", "age", "100"); System.out.println(redisTemplate.opsForHash().entries("testName")); System.out.println(redisTemplate.opsForHash().values("testName")); }测试结果
{name=shizheng, age=100} [shizheng, 100]3.List< HV> values(H key)
根据密钥获取整个散列存储的值,用法如上
4.Map< HK,HV> entries(H key)
根据密钥获取整个散列存储,用法如上
5.Long delete(H key,Object… hashKeys)
删除给定的hashKeys
@Test public void hash3() { redisTemplate.opsForHash().put("testName", "name", "shizheng"); redisTemplate.opsForHash().put("testName", "age", "100"); System.out.println(redisTemplate.opsForHash().delete("testName","name")); System.out.println(redisTemplate.opsForHash().entries("testName")); }测试结果
1 {age=100}6.Boolean hashKey(H key,Object hashKey)
确定hashKey是否存在
@Test public void hash4() { redisTemplate.opsForHash().put("testName", "name", "shizheng"); redisTemplate.opsForHash().put("testName", "age", "100"); System.out.println(redisTemplate.opsForHash().hasKey("testName","name")); System.out.println(redisTemplate.opsForHash().hasKey("testName","height")); }测试结果
true false7.HV get(H key,Object hashKey)
从散列获取给定hashKey的值
具体用法:获取name的值
@Test //从键中的哈希获取给定hashKey的值 public void hash7() { redisTemplate.opsForHash().put("testName", "name", "shizheng"); redisTemplate.opsForHash().put("testName", "sex", "male"); System.out.println(redisTemplate.opsForHash().get("testName", "name")); }测试结果
shizheng8.Set< HK> keys(H key) 获取key所对应的key的值
@Test //获取key所对应的散列表的key public void hash8() { redisTemplate.opsForHash().put("testName", "name", "shizheng"); redisTemplate.opsForHash().put("testName", "sex", "male"); System.out.println(redisTemplate.opsForHash().keys("testName")); }测试结果
[name, sex]9.Long size(H key)
获取key所对应的散列表的大小个数
@Test //获取key所对应的散列表的大小个数 public void hash9() { redisTemplate.opsForHash().put("testName", "name", "shizheng"); redisTemplate.opsForHash().put("testName", "sex", "male"); System.out.println(redisTemplate.opsForHash().size("testName")); }测试结果
21.Long leftPushAll(K key,V… values) 含义:leftPushAll表示把一个数组插入列表中
@Test //批量把一个数组插入到列表中 public void list1() { String[] strings = new String[]{"1", "2", "3"}; redisTemplate.opsForList().leftPushAll("list", strings); System.out.println(redisTemplate.opsForList().range("list", 0, -1)); }输出结果
[3, 2, 1]2.Long size(K key) 含义:返回存储在键中的列表的长度。如果键不存在,则将其解释为空列表,并返回0。当key存储的值不是列表时返回错误。
@Test //返回存储在键中的列表的长度。如果键不存在,则将其解释为空列表,并返回0。当key存储的值不是列表时返回错误。 public void list2() { String[] strings = new String[]{"1", "2", "3"}; redisTemplate.opsForList().leftPushAll("list", strings); System.out.println(redisTemplate.opsForList().size("list")); }测试结果
33 Long leftPush(K key,V value) 含义:将所有指定的值插入在键的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表(从左边插入)。
@Test //将所有指定的值插入存储在键的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表。(从左边插入) public void list3() { redisTemplate.opsForList().leftPush("list", "1"); System.out.println(redisTemplate.opsForList().size("list")); redisTemplate.opsForList().leftPush("list", "2"); System.out.println(redisTemplate.opsForList().size("list")); redisTemplate.opsForList().leftPush("list", "3"); System.out.println(redisTemplate.opsForList().size("list")); }测试结果
1 2 34 Long rightPush(K key,V value) 含义:将所有指定的值插入存储在键的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表。(从右边插入)
@Test //将所有指定的值插入存储在键的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表。(从右边插入) public void list4() { redisTemplate.opsForList().rightPush("listRight", "1"); System.out.println(redisTemplate.opsForList().size("listRight")); redisTemplate.opsForList().rightPush("listRight", "2"); System.out.println(redisTemplate.opsForList().size("listRight")); redisTemplate.opsForList().rightPush("listRight", "3"); System.out.println(redisTemplate.opsForList().size("listRight")); }测试结果
1 2 35 Long rightPushAll(K key,V…values) 含义:通过rightPushAll方法向最右边批量添加元素
@Test // public void list5() { String[] strings = new String[]{"1", "2", "3"}; redisTemplate.opsForList().rightPushAll("list", strings); System.out.println(redisTemplate.opsForList().range("list", 0, -1)); }测试结果
[1, 2, 3]6 void set(K key,long index,V value) 含义:在列表中index的位置设置value
@Test //在列表中index的位置设置value值 public void list6() { String[] strings = new String[]{"1", "2", "3"}; redisTemplate.opsForList().rightPushAll("list6", strings); System.out.println(redisTemplate.opsForList().range("list6", 0, -1)); redisTemplate.opsForList().set("list6", 1, "值"); System.out.println(redisTemplate.opsForList().range("list6", 0, -1)); }测试结果
[1, 2, 3, 1, 2, 3] [1, 值, 3, 1, 2, 3]7 Long remove(K key,long court,Object value) 含义:从存储在键中的列表,删除给定”count“值的元素的第1个计数事件。其中,参数count的含义如下: count=0:删除等于value的所有元素 count>0:删除等于从头到尾移动的值的元素 count<0:删除等于从尾到头移动的值的元素
@Test //删除列表中存储的列表中第一次出现的 public void list7() { String[] strings = new String[]{"1", "2", "3"}; redisTemplate.opsForList().rightPushAll("list7", strings); System.out.println(redisTemplate.opsForList().range("list7", 0, -1)); redisTemplate.opsForList().remove("list7", 1, "2");//将删除列表中存储的列表中第一次出现的“2”。 System.out.println(redisTemplate.opsForList().range("list7", 0, -1)); }测试结果
[1, 2, 3] [1, 3]8 V index(K key,long index) 含义:根据下标获取列表中的值(下标从0开始)
@Test //根据下标获取列表中的值,下标是从0开始的 public void list8() { String[] strings = new String[]{"1", "2", "3"}; redisTemplate.opsForList().rightPushAll("list8", strings); System.out.println(redisTemplate.opsForList().range("list8", 0, -1)); System.out.println(redisTemplate.opsForList().index("list8", 2)); }测试结果
[1, 2, 3] 39 V leftPop(K key) 含义:弹出最左边的元素,弹出之后该值在列表中将不复存在
@Test //弹出最左边的元素,弹出之后该值在列表中将不复存在 public void list9() { String[] strings = new String[]{"1", "2", "3"}; redisTemplate.opsForList().rightPushAll("list9", strings); System.out.println(redisTemplate.opsForList().range("list9", 0, -1)); System.out.println(redisTemplate.opsForList().leftPop("list9")); System.out.println(redisTemplate.opsForList().range("list9", 0, -1)); }测试结果
[1, 2, 3] 3 [1, 2]10 V rightPop(K key) 含义:弹出最右边的元素,弹出之后该值在列表中将不复存在
@Test //弹出最右边的元素,弹出之后该值在列表中将不复存在 public void list10() { String[] strings = new String[]{"1", "2", "3"}; redisTemplate.opsForList().rightPushAll("list10", strings); System.out.println(redisTemplate.opsForList().range("list10", 0, -1)); System.out.println(redisTemplate.opsForList().rightPop("list10")); System.out.println(redisTemplate.opsForList().range("list10", 0, -1)); }测试结果
[1, 2, 1, 2, 3] 3 [1, 2, 1, 2]1 Long add(K key,V…values) 含义:在无序集合中添加元素,返回添加个数
@Test //无序集合中添加元素,返回添加个数 public void Set1() { String[] strs = new String[]{"str1", "str2"}; System.out.println(redisTemplate.opsForSet().add("Set1", strs)); //也可以直接在add里面添加多个值 System.out.println(redisTemplate.opsForSet().add("Set1", "1", "2", "3")); }测试结果
2 Long remove(K key,Object… values) 含义:移除集合中一个或多个成员
@Test //移除集合中一个或多个成员 public void Set2() { String[] strs = new String[]{"str1", "str2"}; System.out.println(redisTemplate.opsForSet().add("Set2", strs)); System.out.println(redisTemplate.opsForSet().remove("set2", strs)); }3.V pop(K key) 含义:移除并返回集合中的一个随机元素
@Test //移除并返回集合中的一个随机元素 public void Set3() { String[] strs = new String[]{"str1", "str2"}; System.out.println(redisTemplate.opsForSet().add("Set3", strs)); System.out.println(redisTemplate.opsForSet().pop("Set3")); System.out.println(redisTemplate.opsForSet().members("Set3")); }4 Boolean move( K key,V value,K destKey) 含义:将member元素移动
@Test //将 member 元素从进行移动 public void Set4() { String[] strs = new String[]{"str1", "str2"}; System.out.println(redisTemplate.opsForSet().add("Set4", strs)); redisTemplate.opsForSet().move("Set4", "str2", "Set4to2"); System.out.println(redisTemplate.opsForSet().members("Set4")); System.out.println(redisTemplate.opsForSet().members("Set4to2")); }5 Long size(K key) 含义:获取无序集合的大小长度
@Test //无序集合的大小长度 public void Set5() { String[] strs = new String[]{"str1", "str2"}; System.out.println(redisTemplate.opsForSet().add("Set5", strs)); System.out.println(redisTemplate.opsForSet().size("Set5")); }6 Set members(K key) 含义:返回集合中的所有成员
@Test //返回集合中的所有成员 public void Set6() { String[] strs = new String[]{"str1", "str2"}; System.out.println(redisTemplate.opsForSet().add("Set6", strs)); System.out.println(redisTemplate.opsForSet().members("Set6")); }7 Cursor< V > scan(K key,ScanOptions options) 含义:遍历set
@Test //遍历set public void Set7() { String[] strs = new String[]{"str1", "str2"}; System.out.println(redisTemplate.opsForSet().add("Set7", strs)); Cursor<Object> curosr = redisTemplate.opsForSet().scan("Set7", ScanOptions.NONE); while (curosr.hasNext()) { System.out.println(curosr.next()); } }1Long add(K key,Set< TypedTuple< V>> tuples) 含义:新增一个有序集合
2 Boolean add(K key,V value,double score) 含义:新增一个有序集合,如果存在则返回false,如果不存在则返回true 3 Long remove(K key,Object… values) 含义:从有序集合中移除一个或多个元素
4 Long rank(K key, Object o) 含义:返回有序集中指定成员的排名,按分数值递增排列
5 Set< V > range(K key,long start,long end) 含义:通过索引区间返回有序集合指定区间内的成员,按分数值递增排列
6 Long court(K key,double min,double max) 含义:通过分数返回有序集合指定区间内的成员个数 7 Long size(K key) 含义:获取有序集合的成员数
8 Double score(K key, Object o) 含义:获取指定成员的score
9 Long removeRange(K key,long start,long end) 含义:移除指定索引位置的成员,有序集合成员按分数值递增排列
10 Cursor < TypedTuple < V > > scan(K key,ScanOptions options) 含义:遍历zset
@Test //新增一个有序集合 public void Zset1() { ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 9.6); ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 9.9); Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>(); tuples.add(objectTypedTuple1); tuples.add(objectTypedTuple2); System.out.println(redisTemplate.opsForZSet().add("zset1", tuples)); System.out.println(redisTemplate.opsForZSet().range("zset1", 0, -1)); } @Test //新增一个有序集合,存在的话为false,不存在的话为true public void Zset2() { System.out.println(redisTemplate.opsForZSet().add("zset2", "zset-1", 1.0)); System.out.println(redisTemplate.opsForZSet().add("zset2", "zset-1", 1.0)); } @Test //从有序集合中移除一个或者多个元素 public void Zset3() { System.out.println(redisTemplate.opsForZSet().add("zset3", "zset-1", 1.0)); System.out.println(redisTemplate.opsForZSet().add("zset3", "zset-2", 1.0)); System.out.println(redisTemplate.opsForZSet().range("zset3", 0, -1)); System.out.println(redisTemplate.opsForZSet().remove("zset3", "zset-2")); System.out.println(redisTemplate.opsForZSet().range("zset3", 0, -1)); } @Test //返回有序集中指定成员的排名,其中有序集成员按分数值递增(从小到大)顺序排列 public void Zset4() { System.out.println(redisTemplate.opsForZSet().add("zset4", "zset-1", 1.0)); System.out.println(redisTemplate.opsForZSet().add("zset4", "zset-2", 1.0)); System.out.println(redisTemplate.opsForZSet().range("zset4", 0, -1)); System.out.println(redisTemplate.opsForZSet().rank("zset4", "zset-1")); } @Test //通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列 public void Zset5() { ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 9.6); ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 9.1); Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>(); tuples.add(objectTypedTuple1); tuples.add(objectTypedTuple2); System.out.println(redisTemplate.opsForZSet().add("zset5", tuples)); System.out.println(redisTemplate.opsForZSet().range("zset5", 0, -1)); } @Test //通过分数返回有序集合指定区间内的成员个数 public void Zset6() { ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6); ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 4.1); ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 5.7); Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>(); tuples.add(objectTypedTuple1); tuples.add(objectTypedTuple2); tuples.add(objectTypedTuple3); System.out.println(redisTemplate.opsForZSet().add("zset6", tuples)); System.out.println(redisTemplate.opsForZSet().rangeByScore("zset6", 0, 9)); System.out.println(redisTemplate.opsForZSet().count("zset6", 0, 5)); } @Test //获取有序集合的成员数 public void Zset7() { ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6); ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 4.1); ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 5.7); Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>(); tuples.add(objectTypedTuple1); tuples.add(objectTypedTuple2); tuples.add(objectTypedTuple3); System.out.println(redisTemplate.opsForZSet().add("zset7", tuples)); System.out.println(redisTemplate.opsForZSet().size("zset7")); } @Test //获取指定成员的score值 public void Zset8() { ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6); ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 4.1); ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 5.7); Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>(); tuples.add(objectTypedTuple1); tuples.add(objectTypedTuple2); tuples.add(objectTypedTuple3); System.out.println(redisTemplate.opsForZSet().add("zset8", tuples)); System.out.println(redisTemplate.opsForZSet().score("zset8", "zset-3")); } @Test //获取指定成员的score值 public void Zset9() { ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6); ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 5.1); ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 2.7); Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>(); tuples.add(objectTypedTuple1); tuples.add(objectTypedTuple2); tuples.add(objectTypedTuple3); System.out.println(redisTemplate.opsForZSet().add("zset9", tuples)); System.out.println(redisTemplate.opsForZSet().range("zset9", 0, -1)); System.out.println(redisTemplate.opsForZSet().removeRange("zset9", 1, 2)); System.out.println(redisTemplate.opsForZSet().range("zset9", 0, -1)); } @Test //遍历zset public void Zset10() { ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6); ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 5.1); ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 2.7); Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>(); tuples.add(objectTypedTuple1); tuples.add(objectTypedTuple2); tuples.add(objectTypedTuple3); System.out.println(redisTemplate.opsForZSet().add("zset10", tuples)); Cursor<ZSetOperations.TypedTuple<Object>> cursor = redisTemplate.opsForZSet().scan("zset10", ScanOptions.NONE); while (cursor.hasNext()) { ZSetOperations.TypedTuple<Object> item = cursor.next(); System.out.println(item.getValue() + ":" + item.getScore()); } } @Test //遍历zset public void Zsetdss() { //有十个库存 Integer count = 100; //添加到redis list中 for (Integer i = 0; i < count; i++) { redisTemplate.opsForList().leftPush("slist", 1); } System.out.println(redisTemplate.opsForList().range("slist", 0, -1)); } @Test //遍历zset public void s2() { //判断计数器 if (redisTemplate.opsForList().size("slist") > 0) { long user_id = 1903; redisTemplate.opsForList().leftPush("ulist", user_id); } System.out.println(redisTemplate.opsForList().range("slist", 0, -1)); System.out.println(redisTemplate.opsForList().range("ulist", 0, -1)); }