课程表

Spring Boot课程

工具箱
速查手册

Boot 使用redis

当前位置:免费教程 » Java相关 » Spring Boot
注意:本页面内容为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>大节添加如下依赖:

  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-data-redis</artifactId>
  4.     <version>2.1.2.RELEASE</version>
  5. </dependency>

然后,让IntelliJ IDEA 自动帮我们下载,我们再到application.yml 中进行相关的配置。我们先简单的设置一个服务器和IP地址(IP请替换成你服务器的IP,可以用内网地址),在spring大节下,增加Redis的配置:

  1. redis:
  2.   host: 192.168.254.32  #这里替换成你的Redis服务器IP,如果是本机,使用localhost即可
  3.   password: mypassword  #这里替换成你的密码

如果你想要得到更多的配置参数,请查阅我们之前的文章:Spring Boot 配置属性之NOSQL

如果你用的是Redis集群,那么配置稍微有所不同,需要在Spring大节下,增加如下配置:

  1. redis:
  2.   password: mypassword  #这里替换成你的密码
  3.   cluster:
  4.     nodes: 192.168.254.10:7000  #这里替换成你的Redis服务器IP和端口

配置好 pom.xml 和 application.yml 后,我们在程序的utils文件夹中,增加一个DateTime类,并添加如下一个方法备用:

  1. //获取当天的最后时刻
  2. public static Date getDayEnd() {
  3.     Calendar cal = Calendar.getInstance();
  4.     cal.set(Calendar.HOUR_OF_DAY, 23);
  5.     cal.set(Calendar.MINUTE, 59);
  6.     cal.set(Calendar.SECOND, 59);
  7.     cal.set(Calendar.MILLISECOND, 999);
  8.     return cal.getTime();
  9. }

我们在MainRestController类中引用DateTime类,并添加如下代码:

  1. import com.w3xue.jiaocheng.utils.DateTime;

添加一个自动装配对象,还有一个Url路由和相应方法:

  1. @Autowired
  2. StringRedisTemplate redisTemplate;//引入redis
  3. @RequestMapping("/redis")
  4. public JSONObject redis() {
  5.     JSONObject result = new JSONObject();
  6.  
  7.     String phone = "18888888888";
  8.     String key = "test:" + phone;
  9.  
  10.     if (redisTemplate.hasKey(key)) { //如果该键有值
  11.         result.put("success", false);
  12.         result.put("ErrorMessage", "您今天已经参与过活动!感谢您的参与,请明天再来!");
  13.     } else {
  14.         result.put("success", true);
  15.         redisTemplate.opsForValue().set(key,"1"); //设置值为1即可,因为只是判断是否有值
  16.         redisTemplate.expireAt(key, DateTime.getDayEnd()); //设置过期时间为当天
  17.         result.put("canPrize", "canPrize");
  18.     }
  19.     return result;
  20. }

此处,我们需要这个依赖包:

  1. import org.springframework.data.redis.core.StringRedisTemplate;

访问“http://localhost:8080/jiaocheng/redis”,第一次返回结果如下:

  1. {"canPrize":"canPrize","success":true}

再次访问,就不一样了,当天的剩下时间都会如此,第二天才会复原:

  1. {"success":false,"ErrorMessage":"您今天已经参与过活动!感谢您的参与,请明天再来!"}

这个StringRedisTemplate类是什么?它实际上继承自RedisTemplate类,这个RedisTemplate类有各种各样的Redis操作方法。虽然StringRedisTemplate类继承自RedisTemplate类,但两者的数据是不共通的,StringRedisTemplate类只能管理申明为该类的对象的数据,而RedisTemplate类也是一样。但StringRedisTemplate类的很多数据结构操作方法,比如本例中使用的opsForValue()方法就是继承自RedisTemplate类的,他们返回相应的对象,这些对象又可以使用其方法操作Redis,常用的有如下数据结构返回方法

  1. redisTemplate.opsForValue();  //操作字符串
  2. redisTemplate.opsForHash();   //操作hash
  3. redisTemplate.opsForList();   //操作list
  4. redisTemplate.opsForSet();    //操作set
  5. redisTemplate.opsForZSet();   //操作有序set
  6. redisTemplate.opsForCluster();  //操作集群

StringRedisTemplate类RedisTemplate类两者之间的区别主要在于他们使用的序列化类:RedisTemplate类使用的是JdkSerializationRedisSerializer序列化类,存入数据会将数据先序列化成字节数组然后在存入Redis数据库。 StringRedisTemplate类使用的是StringRedisSerializer类。两者的机制不同,决定了它们会有细微差异:当你的redis数据库里面本来存的是字符串数据,或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate类即可。但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate类是更好的选择。当redis中存入的数据是可读形式而非字节数组时,使用RedisTemplate类取值的时候会无法获取导出数据,获得的值为null,这时可以使用StringRedisTemplate类试试。这里,我们就使用StringRedisTemplate类,因为它更方便、更快捷。

我们已经看到了一种方法,下面,我们来看看其他常用操作。


二、操作简单的键值

全在代码里了(请将代码放入MainRestController类):

  1. //Spring Boot 操作简单的键值
  2. @RequestMapping("/redisvalue")
  3. public String redisvalue() {
  4.     StringBuilder sbReturn=new StringBuilder();
  5.     redisTemplate.opsForValue().set("testKey", "testKeyValue",60*10, TimeUnit.SECONDS); //向redis里存入数据和设置缓存时间为10分钟
  6.     sbReturn.append(redisTemplate.opsForValue().get("testKey")+"<br />"); //根据key获取缓存中的val
  7.     redisTemplate.opsForValue().set("numKey", "10",60*10, TimeUnit.SECONDS); //设置numKey,并设置过期时间
  8.     redisTemplate.boundValueOps("numKey").increment(-1); //对该键的值做-1操作
  9.     redisTemplate.boundValueOps("numKey").increment(3);//对该键的值+3操作
  10.     sbReturn.append(redisTemplate.opsForValue().get("numKey")+"<br />");
  11.     sbReturn.append(redisTemplate.getExpire("testKey")+"<br />"); //根据key获取过期时间
  12.     sbReturn.append(redisTemplate.getExpire("testKey",TimeUnit.MILLISECONDS)+"<br />");  //根据key获取过期时间并换算成指定单位(毫秒)
  13.     redisTemplate.delete("testKey");//根据key删除缓存
  14.     if (redisTemplate.hasKey("testKey")) //检查key是否存在,返回boolean值
  15.         sbReturn.append("现在testKey的值为:"+redisTemplate.opsForValue().get("testKey")+"<br />");
  16.     else
  17.         sbReturn.append("现在testKey已经被删除了<br />");
  18.     return sbReturn.toString();
  19. }

这里需要引用一个依赖包(一如既往,IntelliJ IDEA会帮你搞定,或者按Alt+Enter):

  1. import java.util.concurrent.TimeUnit;

运行结果(http://localhost:8080/jiaocheng/redisvalue)如下:

  1. testKeyValue
  2. 12
  3. 600
  4. 599981
  5. 现在testKey已经被删除了

更多的关于键值的操作,请点击这里:Boot redis操作键值


三、操作Hash表

Redis的hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。最为方便的是,Java的Hash表可以通过StringRedisTemplate类的方法直接存入Redis。Hash表只有键值对,其成员之间的顺序是无序的(不是指内存地址),因此,使用时会发现,显示的HashTable的成员会错乱。

上代码(请将代码放入MainRestController类

  1. //Spring Boot 操作Hash表(散列表)
  2. @RequestMapping("/redishash")
  3. public String redishash() {
  4.     StringBuilder sbReturn=new StringBuilder();
  5.     Map mapTest=new HashMap();
  6.     mapTest.put("key1","Tom");
  7.     mapTest.put("key2","Jerry");
  8.     mapTest.put("key3","Speike");
  9.     redisTemplate.opsForHash().putAll("redisHash",mapTest); //将HashMap命名为redisHash
  10.     redisTemplate.expire("redisHash",3000 , TimeUnit.MILLISECONDS); //设置redisHash过期时间(毫秒)
  11.     if (redisTemplate.opsForHash().hasKey("redisHash","key1")) //查看设置redisHash中是否有键key1
  12.         sbReturn.append("redisHash中含有键\"key1\",其值为:"+redisTemplate.opsForHash().get("redisHash","key1")+",哈希表全部数据为:"+redisTemplate.opsForHash().entries("redisHash")+"<br />"); //实际显示全部数据时,是随机顺序的
  13.     else
  14.         sbReturn.append("redisHash中没有键\"key1\"!");
  15.     redisTemplate.opsForHash().delete("redisHash","key1"); //删除键key1
  16.     sbReturn.append("经过删除操作后,现在redisHash还有键\"key1\"吗:"+redisTemplate.opsForHash().hasKey("redisHash","key1"));
  17.     return sbReturn.toString();
  18. }

运行结果(http://localhost:8080/jiaocheng/redishash)如下:

  1. redisHash中含有键"key1",其值为:Tom,哈希表全部数据为:{key1=Tom, key2=Jerry, key3=Speike}
  2. 经过删除操作后,现在redisHash还有键"key1"吗:false

更多的关于Hash表的操作,请点击这里:Boot redis操作键值


四、操作List(列表)

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边),一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。

代码如下(请将代码放入MainRestController类):

  1. //Spring Boot 操作List(列表)
  2. @RequestMapping("/redislist")
  3. public String redislist() {
  4.     StringBuilder sbReturn=new StringBuilder();
  5.     List<String> listPrime=new ArrayList<String>();
  6.     listPrime.add("2");
  7.     listPrime.add("3");
  8.     listPrime.add("5");
  9.     listPrime.add("7");
  10.     listPrime.add("11");
  11.     redisTemplate.opsForList().rightPushAll("redisList",listPrime); //将listPrime的成员,按从左到右的顺序,整个注入redisList
  12.     redisTemplate.expire("redisList",3000 , TimeUnit.MILLISECONDS); //设置过期时间(毫秒)
  13.     redisTemplate.opsForList().rightPush("redisList","13"); //将13放到list的结尾,left
  14.     redisTemplate.opsForList().remove("redisList",0,"7"); //根据值删除成员,此处删除值为7的成员
  15.     //count> 0:删除等于从左到右移动的值的第一个元素;count< 0:删除等于从右到左移动的值的第一个元素;count = 0:删除等于value的所有元素。
  16.     //还有种说法是count<0时删除了整个list,count>=0是删除的是等于value的所有元素
  17.     //但实际的作用是,小于0时,会删除从右到左找到的第一个元素,而大于等于0,就是删除所有等于这个值的元素,版本?
  18.     sbReturn.append("redisList中索引为3的成员的值为:"+redisTemplate.opsForList().index("redisList",3).toString()+"<br />");
  19.     sbReturn.append("redisList中成员数量为:"+redisTemplate.opsForList().size("redisList")+"<br />");
  20.     return sbReturn.toString();
  21. }

注意其中的“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)如下:

  1. 删除后redisList中索引为3的成员的值为:11
  2. 删除后redisList中成员数量为:5

更多的关于Hash表的操作,请点击这里:Boot redis操作List


五、操作Set(集合)

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

代码如下(请将代码放入MainRestController类):

  1. //Spring Boot 操作Set(集合)
  2. @RequestMapping("/redisset")
  3. public String redisset() {
  4.     StringBuilder sbReturn=new StringBuilder();
  5.     redisTemplate.opsForSet().add("setKey", "1","2","3"); //向指定key中存放set集合
  6.     redisTemplate.expire("setKey",3000 , TimeUnit.MILLISECONDS); //设置过期时间(毫秒)
  7.     if (redisTemplate.opsForSet().isMember("setKey", "1")) //根据key查看集合中是否存在指定数据
  8.         sbReturn.append("setKey中含有数据\"1\",集合全部数据为:"+redisTemplate.opsForSet().members("setKey")+"<br />"); //根据key获取set集合
  9.     else
  10.         sbReturn.append("setKey中没有数据\"1\"!");
  11.     return sbReturn.toString();
  12. }

运行结果(http://localhost:8080/jiaocheng/redisset)如下:

  1. setKey中含有数据"1",集合全部数据为:[1, 2, 3]

更多的关于Hash表的操作,请点击这里:Boot redis操作集合


六、操作ZSet(有序集合)

代码如下(请将代码放入MainRestController类):

  1. //Spring Boot 操作ZSet(有序集合)
  2. @RequestMapping("/rediszset")
  3. public String rediszset() {
  4.     StringBuilder sbReturn=new StringBuilder();
  5.     redisTemplate.opsForZSet().add("redisZSet","Alice",10); //向指定key中存放set集合
  6.     redisTemplate.opsForZSet().add("redisZSet","Bob",20);
  7.     redisTemplate.opsForZSet().add("redisZSet","Chris",30);
  8.     redisTemplate.opsForZSet().add("redisZSet","David",40);
  9.     redisTemplate.expire("redisZSet",3000 , TimeUnit.MILLISECONDS); //设置过期时间(毫秒)
  10.     sbReturn.append("redisZSet中Chris的值为:"+redisTemplate.opsForZSet().score("redisZSet","Chris")+"<br />"); //根据key获取成员值
  11.     sbReturn.append("redisZSet中Bob的索引为:"+redisTemplate.opsForZSet().rank("redisZSet","Bob")+"<br />");
  12.     sbReturn.append("redisZSet的成员数:"+redisTemplate.opsForZSet().size("redisZSet")+"<br />"); //获取有序集合的成员数,其内部调用的就是zCard方法
  13.     sbReturn.append("redisZSet的总共有几个成员变量:"+redisTemplate.opsForZSet().zCard("redisZSet")+"<br />"); //推荐使用的统计成员数的方法
  14.     sbReturn.append("显示redisZSet的所有键:"+redisTemplate.opsForZSet().range("redisZSet",0,100)+"<br />"); //注意0为开始的索引,100为结束的索引
  15.     sbReturn.append("反向显示redisZSet的所有键:"+redisTemplate.opsForZSet().reverseRange("redisZSet",0,100)+"<br />"); //0为开始的索引,100为结束的索引
  16.     sbReturn.append("打印redisZSet的所有键和值:<br />--------------<br />");
  17.     Cursor<ZSetOperations.TypedTuple<String>> cursor = redisTemplate.opsForZSet().scan("redisZSet", ScanOptions.NONE);
  18.     while (cursor.hasNext()){
  19.         ZSetOperations.TypedTuple<String> typedTuple = cursor.next(); //将下一个cursor的成员赋值给typedTuple
  20.         sbReturn.append(typedTuple.getValue() + ":" + typedTuple.getScore()+"<br />"); //分别打印键和值
  21.     }
  22.     sbReturn.append("--------------<br />");
  23.     sbReturn.append("redisZSet中,值在15-35之间成员的个数:"+redisTemplate.opsForZSet().count("redisZSet",15,35).toString()+"<br />"); //注意15为较小值,35为较大值
  24.     sbReturn.append("一次性删除:"+redisTemplate.opsForZSet().remove("redisZSet","Chris","David")+"个键<br />"); //这个方法返回被删除键的个数
  25.     sbReturn.append("删除操作后,redisZSet中Chris的值为:"+redisTemplate.opsForZSet().score("redisZSet","Chris")+"<br />");
  26.     sbReturn.append("删除操作后,redisZSet的总共有几个成员变量:"+redisTemplate.opsForZSet().zCard("redisZSet")+"<br />");
  27.     return sbReturn.toString();
  28. }

运行结果(http://localhost:8080/jiaocheng/rediszset)如下:

  1. redisZSetChris的值为:30.0
  2. redisZSetBob的索引为:1
  3. redisZSet的成员数:4
  4. redisZSet的总共有几个成员变量:4
  5. 显示redisZSet的所有键:[Alice, Bob, Chris, David]
  6. 反向显示redisZSet的所有键:[David, Chris, Bob, Alice]
  7. 打印redisZSet的所有键和值:
  8. --------------
  9. Alice10.0
  10. Bob20.0
  11. Chris30.0
  12. David40.0
  13. --------------
  14. redisZSet中,值在15-35之间成员的个数:2
  15. 一次性删除:2个键
  16. 删除操作后,redisZSetChris的值为:null
  17. 删除操作后,redisZSet的总共有几个成员变量:2

更多的关于Hash表的操作,请点击这里:Boot redis操作有序集合

注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2019/10/18 17:15:14
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号