Boot 使用redis
注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue 发布时间:2019/10/18 17:15:14
Redis是一种常用的键值存储系统,其快速、灵活、小巧,让它受到了普遍的欢迎。那么,Spring Boot如何使用Redis呢?实际上是非常方便的。
在学习本节之前,你需要先安装并学习Redis,点此进入w3xue的Redis教程。Redis使用起来非常简单,学习起来很快,如果你之前没有学习过,去花一点时间学习一下,再回来学习也是可以的。在这里,我们默认你已经安装好了Redis,且已经学习了Redis的使用。
一、准备和基本示例
首先,我们在pom.xml中引入相关依赖,然后IntelliJ IDEA 会帮我们自动下载、导入依赖包。在pom.xml的<dependencies>大节添加如下依赖:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- <version>2.1.2.RELEASE</version>
- </dependency>
然后,让IntelliJ IDEA 自动帮我们下载,我们再到application.yml 中进行相关的配置。我们先简单的设置一个服务器和IP地址(IP请替换成你服务器的IP,可以用内网地址),在spring大节下,增加Redis的配置:
- redis:
- host: 192.168.254.32 #这里替换成你的Redis服务器IP,如果是本机,使用localhost即可
- password: mypassword #这里替换成你的密码
如果你想要得到更多的配置参数,请查阅我们之前的文章:Spring Boot 配置属性之NOSQL。
如果你用的是Redis集群,那么配置稍微有所不同,需要在Spring大节下,增加如下配置:
- redis:
- password: mypassword #这里替换成你的密码
- cluster:
- nodes: 192.168.254.10:7000 #这里替换成你的Redis服务器IP和端口
配置好 pom.xml 和 application.yml 后,我们在程序的utils文件夹中,增加一个DateTime类,并添加如下一个方法备用:
- //获取当天的最后时刻
- public static Date getDayEnd() {
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.HOUR_OF_DAY, 23);
- cal.set(Calendar.MINUTE, 59);
- cal.set(Calendar.SECOND, 59);
- cal.set(Calendar.MILLISECOND, 999);
- return cal.getTime();
- }
我们在MainRestController类中引用DateTime类,并添加如下代码:
- import com.w3xue.jiaocheng.utils.DateTime;
添加一个自动装配对象,还有一个Url路由和相应方法:
- @Autowired
- StringRedisTemplate redisTemplate;//引入redis
- @RequestMapping("/redis")
- public JSONObject redis() {
- JSONObject result = new JSONObject();
- String phone = "18888888888";
- String key = "test:" + phone;
- if (redisTemplate.hasKey(key)) { //如果该键有值
- result.put("success", false);
- result.put("ErrorMessage", "您今天已经参与过活动!感谢您的参与,请明天再来!");
- } else {
- result.put("success", true);
- redisTemplate.opsForValue().set(key,"1"); //设置值为1即可,因为只是判断是否有值
- redisTemplate.expireAt(key, DateTime.getDayEnd()); //设置过期时间为当天
- result.put("canPrize", "canPrize");
- }
- return result;
- }
此处,我们需要这个依赖包:
- import org.springframework.data.redis.core.StringRedisTemplate;
访问“http://localhost:8080/jiaocheng/redis”,第一次返回结果如下:
- {"canPrize":"canPrize","success":true}
再次访问,就不一样了,当天的剩下时间都会如此,第二天才会复原:
- {"success":false,"ErrorMessage":"您今天已经参与过活动!感谢您的参与,请明天再来!"}
这个StringRedisTemplate类是什么?它实际上继承自RedisTemplate类,这个RedisTemplate类有各种各样的Redis操作方法。虽然StringRedisTemplate类继承自RedisTemplate类,但两者的数据是不共通的,StringRedisTemplate类只能管理申明为该类的对象的数据,而RedisTemplate类也是一样。但StringRedisTemplate类的很多数据结构操作方法,比如本例中使用的opsForValue()方法就是继承自RedisTemplate类的,他们返回相应的对象,这些对象又可以使用其方法操作Redis,常用的有如下数据结构返回方法:
- redisTemplate.opsForValue(); //操作字符串
- redisTemplate.opsForHash(); //操作hash
- redisTemplate.opsForList(); //操作list
- redisTemplate.opsForSet(); //操作set
- redisTemplate.opsForZSet(); //操作有序set
- redisTemplate.opsForCluster(); //操作集群
StringRedisTemplate类和RedisTemplate类两者之间的区别主要在于他们使用的序列化类:RedisTemplate类使用的是JdkSerializationRedisSerializer序列化类,存入数据会将数据先序列化成字节数组然后在存入Redis数据库。 而StringRedisTemplate类使用的是StringRedisSerializer类。两者的机制不同,决定了它们会有细微差异:当你的redis数据库里面本来存的是字符串数据,或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate类即可。但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate类是更好的选择。当redis中存入的数据是可读形式而非字节数组时,使用RedisTemplate类取值的时候会无法获取导出数据,获得的值为null,这时可以使用StringRedisTemplate类试试。这里,我们就使用StringRedisTemplate类,因为它更方便、更快捷。
我们已经看到了一种方法,下面,我们来看看其他常用操作。
二、操作简单的键值
全在代码里了(请将代码放入MainRestController类):
- //Spring Boot 操作简单的键值
- @RequestMapping("/redisvalue")
- public String redisvalue() {
- StringBuilder sbReturn=new StringBuilder();
- redisTemplate.opsForValue().set("testKey", "testKeyValue",60*10, TimeUnit.SECONDS); //向redis里存入数据和设置缓存时间为10分钟
- sbReturn.append(redisTemplate.opsForValue().get("testKey")+"<br />"); //根据key获取缓存中的val
- redisTemplate.opsForValue().set("numKey", "10",60*10, TimeUnit.SECONDS); //设置numKey,并设置过期时间
- redisTemplate.boundValueOps("numKey").increment(-1); //对该键的值做-1操作
- redisTemplate.boundValueOps("numKey").increment(3);//对该键的值+3操作
- sbReturn.append(redisTemplate.opsForValue().get("numKey")+"<br />");
- sbReturn.append(redisTemplate.getExpire("testKey")+"<br />"); //根据key获取过期时间
- sbReturn.append(redisTemplate.getExpire("testKey",TimeUnit.MILLISECONDS)+"<br />"); //根据key获取过期时间并换算成指定单位(毫秒)
- redisTemplate.delete("testKey");//根据key删除缓存
- if (redisTemplate.hasKey("testKey")) //检查key是否存在,返回boolean值
- sbReturn.append("现在testKey的值为:"+redisTemplate.opsForValue().get("testKey")+"<br />");
- else
- sbReturn.append("现在testKey已经被删除了<br />");
- return sbReturn.toString();
- }
这里需要引用一个依赖包(一如既往,IntelliJ IDEA会帮你搞定,或者按Alt+Enter):
- import java.util.concurrent.TimeUnit;
运行结果(http://localhost:8080/jiaocheng/redisvalue)如下:
- testKeyValue
- 12
- 600
- 599981
- 现在testKey已经被删除了
更多的关于键值的操作,请点击这里:Boot redis操作键值。
三、操作Hash表
Redis的hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。最为方便的是,Java的Hash表可以通过StringRedisTemplate类的方法直接存入Redis。Hash表只有键值对,其成员之间的顺序是无序的(不是指内存地址),因此,使用时会发现,显示的HashTable的成员会错乱。
上代码(请将代码放入MainRestController类):
- //Spring Boot 操作Hash表(散列表)
- @RequestMapping("/redishash")
- public String redishash() {
- StringBuilder sbReturn=new StringBuilder();
- Map mapTest=new HashMap();
- mapTest.put("key1","Tom");
- mapTest.put("key2","Jerry");
- mapTest.put("key3","Speike");
- redisTemplate.opsForHash().putAll("redisHash",mapTest); //将HashMap命名为redisHash
- redisTemplate.expire("redisHash",3000 , TimeUnit.MILLISECONDS); //设置redisHash过期时间(毫秒)
- if (redisTemplate.opsForHash().hasKey("redisHash","key1")) //查看设置redisHash中是否有键key1
- sbReturn.append("redisHash中含有键\"key1\",其值为:"+redisTemplate.opsForHash().get("redisHash","key1")+",哈希表全部数据为:"+redisTemplate.opsForHash().entries("redisHash")+"<br />"); //实际显示全部数据时,是随机顺序的
- else
- sbReturn.append("redisHash中没有键\"key1\"!");
- redisTemplate.opsForHash().delete("redisHash","key1"); //删除键key1
- sbReturn.append("经过删除操作后,现在redisHash还有键\"key1\"吗:"+redisTemplate.opsForHash().hasKey("redisHash","key1"));
- return sbReturn.toString();
- }
运行结果(http://localhost:8080/jiaocheng/redishash)如下:
- redisHash中含有键"key1",其值为:Tom,哈希表全部数据为:{key1=Tom, key2=Jerry, key3=Speike}
- 经过删除操作后,现在redisHash还有键"key1"吗:false
更多的关于Hash表的操作,请点击这里:Boot redis操作键值。
四、操作List(列表)
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边),一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
代码如下(请将代码放入MainRestController类):
- //Spring Boot 操作List(列表)
- @RequestMapping("/redislist")
- public String redislist() {
- StringBuilder sbReturn=new StringBuilder();
- List<String> listPrime=new ArrayList<String>();
- listPrime.add("2");
- listPrime.add("3");
- listPrime.add("5");
- listPrime.add("7");
- listPrime.add("11");
- redisTemplate.opsForList().rightPushAll("redisList",listPrime); //将listPrime的成员,按从左到右的顺序,整个注入redisList
- redisTemplate.expire("redisList",3000 , TimeUnit.MILLISECONDS); //设置过期时间(毫秒)
- redisTemplate.opsForList().rightPush("redisList","13"); //将13放到list的结尾,left
- redisTemplate.opsForList().remove("redisList",0,"7"); //根据值删除成员,此处删除值为7的成员
- //count> 0:删除等于从左到右移动的值的第一个元素;count< 0:删除等于从右到左移动的值的第一个元素;count = 0:删除等于value的所有元素。
- //还有种说法是count<0时删除了整个list,count>=0是删除的是等于value的所有元素
- //但实际的作用是,小于0时,会删除从右到左找到的第一个元素,而大于等于0,就是删除所有等于这个值的元素,版本?
- sbReturn.append("redisList中索引为3的成员的值为:"+redisTemplate.opsForList().index("redisList",3).toString()+"<br />");
- sbReturn.append("redisList中成员数量为:"+redisTemplate.opsForList().size("redisList")+"<br />");
- return sbReturn.toString();
- }
注意其中的“remove”方法,其第二个参数,我们暂将其称为paraDel,网上的一种说法是:paraDel> 0时,删除从左到右第一个等于value的元素(即第三个参数);paraDel< 0时,删除从右到左第一个等于value的元素;paraDel= 0时,删除所有等于value的所有元素。
还有种说法是paraDel<0时删除了整个list,paraDel>=0是删除的所有等于value的元素。
但实际过程中,w3xue发现:paraDel<0时,会删除从右到左找到的第一个元素,而paraDel>=0时,就是删除所有等于这个值的元素,这可能是版本的原因导致的,如果你在使用过程中发现了之前提过的2种表现,则以它们为准。在此,我们建议,尽量不设置重复的成员值。
运行结果(http://localhost:8080/jiaocheng/redislist)如下:
- 删除后redisList中索引为3的成员的值为:11
- 删除后redisList中成员数量为:5
更多的关于Hash表的操作,请点击这里:Boot redis操作List。
五、操作Set(集合)
Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
代码如下(请将代码放入MainRestController类):
- //Spring Boot 操作Set(集合)
- @RequestMapping("/redisset")
- public String redisset() {
- StringBuilder sbReturn=new StringBuilder();
- redisTemplate.opsForSet().add("setKey", "1","2","3"); //向指定key中存放set集合
- redisTemplate.expire("setKey",3000 , TimeUnit.MILLISECONDS); //设置过期时间(毫秒)
- if (redisTemplate.opsForSet().isMember("setKey", "1")) //根据key查看集合中是否存在指定数据
- sbReturn.append("setKey中含有数据\"1\",集合全部数据为:"+redisTemplate.opsForSet().members("setKey")+"<br />"); //根据key获取set集合
- else
- sbReturn.append("setKey中没有数据\"1\"!");
- return sbReturn.toString();
- }
运行结果(http://localhost:8080/jiaocheng/redisset)如下:
- setKey中含有数据"1",集合全部数据为:[1, 2, 3]
更多的关于Hash表的操作,请点击这里:Boot redis操作集合。
六、操作ZSet(有序集合)
代码如下(请将代码放入MainRestController类):
- //Spring Boot 操作ZSet(有序集合)
- @RequestMapping("/rediszset")
- public String rediszset() {
- StringBuilder sbReturn=new StringBuilder();
- redisTemplate.opsForZSet().add("redisZSet","Alice",10); //向指定key中存放set集合
- redisTemplate.opsForZSet().add("redisZSet","Bob",20);
- redisTemplate.opsForZSet().add("redisZSet","Chris",30);
- redisTemplate.opsForZSet().add("redisZSet","David",40);
- redisTemplate.expire("redisZSet",3000 , TimeUnit.MILLISECONDS); //设置过期时间(毫秒)
- sbReturn.append("redisZSet中Chris的值为:"+redisTemplate.opsForZSet().score("redisZSet","Chris")+"<br />"); //根据key获取成员值
- sbReturn.append("redisZSet中Bob的索引为:"+redisTemplate.opsForZSet().rank("redisZSet","Bob")+"<br />");
- sbReturn.append("redisZSet的成员数:"+redisTemplate.opsForZSet().size("redisZSet")+"<br />"); //获取有序集合的成员数,其内部调用的就是zCard方法
- sbReturn.append("redisZSet的总共有几个成员变量:"+redisTemplate.opsForZSet().zCard("redisZSet")+"<br />"); //推荐使用的统计成员数的方法
- sbReturn.append("显示redisZSet的所有键:"+redisTemplate.opsForZSet().range("redisZSet",0,100)+"<br />"); //注意0为开始的索引,100为结束的索引
- sbReturn.append("反向显示redisZSet的所有键:"+redisTemplate.opsForZSet().reverseRange("redisZSet",0,100)+"<br />"); //0为开始的索引,100为结束的索引
- sbReturn.append("打印redisZSet的所有键和值:<br />--------------<br />");
- Cursor<ZSetOperations.TypedTuple<String>> cursor = redisTemplate.opsForZSet().scan("redisZSet", ScanOptions.NONE);
- while (cursor.hasNext()){
- ZSetOperations.TypedTuple<String> typedTuple = cursor.next(); //将下一个cursor的成员赋值给typedTuple
- sbReturn.append(typedTuple.getValue() + ":" + typedTuple.getScore()+"<br />"); //分别打印键和值
- }
- sbReturn.append("--------------<br />");
- sbReturn.append("redisZSet中,值在15-35之间成员的个数:"+redisTemplate.opsForZSet().count("redisZSet",15,35).toString()+"<br />"); //注意15为较小值,35为较大值
- sbReturn.append("一次性删除:"+redisTemplate.opsForZSet().remove("redisZSet","Chris","David")+"个键<br />"); //这个方法返回被删除键的个数
- sbReturn.append("删除操作后,redisZSet中Chris的值为:"+redisTemplate.opsForZSet().score("redisZSet","Chris")+"<br />");
- sbReturn.append("删除操作后,redisZSet的总共有几个成员变量:"+redisTemplate.opsForZSet().zCard("redisZSet")+"<br />");
- return sbReturn.toString();
- }
运行结果(http://localhost:8080/jiaocheng/rediszset)如下:
- redisZSet中Chris的值为:30.0
- redisZSet中Bob的索引为:1
- redisZSet的成员数:4
- redisZSet的总共有几个成员变量:4
- 显示redisZSet的所有键:[Alice, Bob, Chris, David]
- 反向显示redisZSet的所有键:[David, Chris, Bob, Alice]
- 打印redisZSet的所有键和值:
- --------------
- Alice:10.0
- Bob:20.0
- Chris:30.0
- David:40.0
- --------------
- redisZSet中,值在15-35之间成员的个数:2
- 一次性删除:2个键
- 删除操作后,redisZSet中Chris的值为:null
- 删除操作后,redisZSet的总共有几个成员变量:2
更多的关于Hash表的操作,请点击这里:Boot redis操作有序集合。
注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue 发布时间:2019/10/18 17:15:14