课程表

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>大节添加如下依赖:

<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

配置好这2个后,我们在程序的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