Redis非关系型数据库总结

redis是基于C语言编写的一个内存中的数据存储系统

 

redis是否为单线程问题:

    redis对于用户来说是单线程的,但其实在redis之后内部是使用了多线程的,像网络传输(即我们连接上redis服务器),也是使用了多线程的

 

可视化:

    使用 Redis-Desktop-Manager 登录

    如果要远程连接,必须关闭只允许本地连接,修改config:

        1.把bind修改掉,要么在后面追加,要么直接注释掉(这就允许全部IP登录)

        2.把protect-mode改成no

        3.还要把防火墙设置放开端口

 

数据库逻辑:

    当连接进入redis服务器的时候,是使用了逻辑分割的形式来创建数据库,并不是真的给你开辟空间放入数据

 

一些配置:

    1.修改密码 -> 修改config

        linux系统在vim模式下可以用 / 来启用搜索模式,小写n搜索下一个,大写N搜索上一个

            :set nu 开启显示行数

        修改里面的requirepass,就可以修改密码了

    2.修改默认数据库数量 -> 修改databases xxx

 

Redis cli连接redis:

    使用Redis cli连接redis,-h指定IP地址,-p指定端口,-a指定密码

    S -> PING    R -> PONG    用于查看连接情况

    select xxx        用于指定需要连接的数据库 例如select 1

    dbsize        用于查看目前数据库有多少条目

    

    String类型

        单个增加:set key value [optional]

            例如:set 姓名 李四

        批量增加:mset key value [key value ...]    mset -> multiple set

            例如:mset 姓名 李四 性别 男

        单个获取:get key

            例如:get 姓名

        批量获取:mget key [key ...]

            例如:mget 姓名 性别

        删除操作:del key [key ...]

            例如:del 姓名 性别

 

    hash类型

        单个增加:hset key field value    其中key是原本redis的key值,而由于我们存放在redis中的value是hash,hash有自己的key:value,那么field对应key,value对应value

            例如:hset user username lisi

        批量增加:hmset key field value [field value ...]

            例如:hmset user username lisi password 123456

        单个获取:hget key field value    其中key是原本redis的key值,而由于我们存放在redis中的value是hash,hash有自己的key:value,那么field对应key,value对应value

            例如:hget user username

        批量增加:hmget key field value [field value ...]

            例如:hmget user username password

        取出所有的hash值:hgetall key

            例如: hgetall user

        删除字段:hdel key field [field ...]

            例如:hdel user username password

 

    list集合类型

        1.添加:

        左添加:lpush key value [value ...]

        例如:lpush student 张三 李四 王五

        左添加的数据是在最左边依次添加,把后面的元素都依次往后排一位

        右添加:rpush key value [value ...]

        例如:rpush student 王五 李四 张三

        右添加的数据是在最后边依次添加,并不存在需要后推之类的操作

 

        2.列表查询:lrange key start stop

            里面的start和stop是以索引值的方式来输入的,如果我们输入了0 2就是查找三条数据

            如果是输入了-1就是查询全部

            如果超过存在的index的话也是查询全部

        

        3.列表删除:lrem key count value

            由于list是可以重复的,那么count就是你想要删除多少个这样的value值

            从最前面开始删除,如果大于现有数量的话就全删除

 

    set集合类型 -> 无序的

        1.添加数据:sadd key member [menber ...]     sadd -> set add

             例如:sadd student zhangsan lisi wangwu

            

        2.查询数据:smember key

            例如:smember student

        

        3.查询行数:scard key

            例如:scard student

    

        4.删除:srem key member [member ...]

            例如:srem student wangwu lisi

 

    sortset集合类型 -> 有序的

        1.添加数据:zadd key score member [score member ...]

            其中score表示你的排序依据

            例如:zadd student 10 zhangsan 8 lisi 3 wangwu

 

        2.查询数据:zrange key start stop [WITHSCORES]

            例如:zrange student 0 2

            

        3.查询行数:zcard key

            例如:zcard student

        

        4.删除数据:zrem key member [member ...]

            例如:srem student wangwu lisi

    

    通用操作:

1.删除:del key [key ...]

2.查询:    keys 通配符

例如:keys *

 

    层级目录:(和realease key有关)

        set 第一层:第二层:***:最后一层 value

        例如: set user:user01:cart iphone

         set user:user02:cart xiaomi

 

失效时间:

    场景:

手机验证码方式登录 -> 用户申请验证码 -> 发送一个验证码并存放在redis ->前端传来的验证码与redis储存的验证码是否一致 -> 验证成功 / 验证失败

    验证码不能长时间有效 -> 别人能无限用这个验证码,被窃取之后不安全

    

    失效时间在redis的实现:

在上面场景中,redis可以设置一个有效时间,当存放进来的数据到达了有效时间,redis就会自动将这条数据删除掉

    

    失效时间的设置:

        可以使用 [ttl | pttl] key 来查看还剩多少[秒 | 毫秒]

        **[NX | XX]的意义:**

        当设置为NX的时候,表示如果这个key不存在我们才能设置成功

        当设置为XX的时候,表示如果这个key存在我们才能设置成功

        就相当于一个锁 -> 当没有的时候我们才能操作,如果有了我们就不能操作,这样数据就不冲突,不会把原来的数据刷下去

        最好和失效时间一起使用

        ①redis lua分布式锁     ②red lock红锁

 

        设置值的时候设置失效时间:

set key value [ex second | px millonsecond] [NX | XX]

        当我们设置失效时间为ex的时候,失效时间为秒;当我们设置失效时间为px的时候,失效时间为毫秒,秒数-1表示永不失效,-2表示已经失效

        例如:set code 403 ex 10

 

        2.设置key的时候设置失效时间:

[expire | pexpire] key second

        当key已经存在的时候,即我们已经把这条数据加入redis的时候,可以使用设置key失效的方式实现失效时间

        例如:expire code 10

 

持久化储存:

    RDB储存:

        指令 -> bgsave

给当前redis获取快照,默认输出是dump.rdb文件,下次加载的时候会读取这个文件重新构建redis数据库

        问题:我们不确定什么时候redis会宕机,我们在每一条命令之后都要bgsave吗?

        解决:在配置文件可以修改

dbfilename:对应的是快照文件名

            dir:存放位置,必须是一个文件夹

            save <seconds> <changes>:seconds表示在多少秒后,changes表示至少多少个key被修改了

            例如:save 30 1:在30秒后,如果有一个key被修改了,就保存一下

        RDB快照的优缺点:

            优点:不用去手动bgsave

            缺点:仍然有数据丢失的风险。我本来有10000个key,在50秒的时候存了9000个之后宕机了,那么这个数据就丢失了,因为还没到阈值

 

    AOF储存:

        修改配置:appendonly 修改为yes

        如果启动了,默认RDB储存方式就会失效,当重启redis之后,并不会去读取rdb文件去获取原有的rdb数据

        优点:AOF储存是实时储存,所有数据都不会丢失

        缺点:数据储存会比RDB更大,而且因为你在不断的做操作,所以数据量会越来越多

        原理:你所做的全部操作都会记录在aof文件中,当你重新启动时,会重新进行这些操作,以致数据不丢失,类似于PacketTracer的配置脚本

        

Redis集群:

    如果不做集群:

        优点:部署简单

        缺点

1. 单点故障:如果宕机了无法使用了

            2. 读的压力会很大:因为Redis是做缓存的,需要经常读取,但是不是频繁变更,所以读取的压力会很大

 

    解决方法 ->主从:

        不可用规则:如果整个集群坏的节点没有超过总节点数的 1/2 ,就是可用的;超过了就是不可用了

        所以集群都是 单数节点部署 / 奇数节点部署

 

        主从概念:

            场景:买火车票

            主:窗口售票

            从:取票机取票

            由于从的出现,分流了主的很多压力,如果任一主机不可用了,另外主机依然可以使用,这样减轻了压力,还能继续提供服务

        主从设计:

            主 服务器修改配置:

                ->修改自己的密码

                ->把保护模式关闭

            从 节点设置:

                ->修改自己的密码

                ->把保护模式关闭

                ->设置 replicaof 主IP 主PORT

                ->设置 masterauth 主密码

 

        可以在主服务器输入 INFO replication 查看现在的主从信息

        在 主 节点放入的值在 从 节点也能获取,通过发布和订阅机制,复制一份拷贝到从节点

        从节点读写:配置 replica-read-only yes/no 不推荐写

        

        主从切换:

如果主节点宕机,就没办法写入数据,只能读取老数据(脏数据)

 

        解决->哨兵(Sentinel)机制:

        哨兵会监控整个主从环境,当检测到主节点宕机之后,会从剩下的节点中自动选举新的主节点,变成新的主节点之后就拥有了写能力,同时把其他从节点关联到新的主节点上

            当原有主节点恢复后,主节点会恢复成主节点,由从节点变为主节点的节点会恢复到从节点

 

Redis缓存存在的问题:

    1. Key的过期淘汰机制

        1.1 定期删除:

Redis其实并不是到期就删除,redis会每隔100ms就随机抽查一些Key,如果已经过期,就删除

        为什么是抽查呢? 因为如果数据量大的话,每隔100ms就全部检查一次,会很耗费资源

        

        1.2 惰性删除:

Redis不去自己删除过期的Key,当用户去Redis查询这个Key的时候,如果Redis检查到这个用户请求的Key已经过期了的话,就删除,并给予用户一个新的Key

        1.3 内存淘汰机制:

如果是使用定期删除+惰性删除,会出现一个问题

        如果定期删除留下了很多过期的Key,而这些Key并没有被用户请求,那么就会留下很多无用Key在Redis里

        解决方法:内存淘汰机制

1. volatile-lru -> Least recent used 找最近最少使用的过期Key删除 (推荐)

        2. volatile-ttl -> 找最近过期的Key删除

        3. volatile-random -> 任意选择过期的Key进行删除

        4. allkeys-lru -> Least recent used 当内存不足时,在全部数据中找最近最少使用的Key删除,并写入新数据

        5. allkeys-ramdom -> 当内存不足时,在所有数据中随机删除数据,并写入新数据

        6. no-enviction -> 当内存不足时,写入新数据直接抛出错误

 

    2. 有哪些应该设置过期时间呢?

对于一些配置文件而言,可以不设置过期时间,对于一般数据而言,可以设置一个过期时间,如果失效了就重新存入Redis中

 

    3. 缓存击穿:

        正常来说一般数据是放在数据库里面,如果要查询再搬到Redis

        场景:双十一晚上11:59一个商品的Key过期了,缓存时间还没到,但是用户在大量的查询,导致用户直接击穿了缓存到数据库查询数据

        一般不会造成数据库宕机,但是会导致数据库压力周期性的增加

        解决方案:

1.可以在Redis不设置过期时间,但是在缓存的对象中加入一个属性用于标识过期的时间,当每次读取这个数据时,转换成java对象后会查询相应的时间是否即将过期,如果是的话,自动产生一个异步进程去请求新的数据

但是有可能会让用户获取到旧数据:当你还剩5s过期时请求了新数据,但是返回给用户的还是旧数据

        2.如果要数据必须是新数据,最好的方法设置永不过期,再加一个互斥锁保证缓存的最新性->即让它和数据库保持同步最新

 

    4. 缓存穿透:

        当Redis和数据库都不存在这个数据的话,如果有攻击者去大量查询这个不存在的数据,就会直接访问到数据库,造成缓存穿透

        解决方法:

        1. 设置异步锁

        2. 采用异步更新,无论key能不能取到,都直接返回,其他步骤就类似于缓存击穿的解决方法1,要预热Redis

        3. 过滤非法的请求参数

        4. 如果数据库查询为空,也写入Redis,不过设置value为空,并且失效时间也要短,60s左右

 

    5. 缓存雪崩

        如果有大量Key在同一时间失效,那么就会发生大量缓存击穿现象,导致数据库压力巨大,甚至宕机

        解决方法:

        1. 给缓存设置一个随机的失效时间,避免集体失效,如果设置了集群,将热门的数据分发在不同的从服务器可以避免全部失效

        2. 使用互斥锁

        3. 设置热点数据永不过期

        4. 双缓存:设置两个缓存A和B,缓存A设置过期时间,但是B设置永不过期,对缓存做预热操作,然后要:

            1. 从缓存A读数据库,如果有就返回

            2. 如果A没有,就读B的,返回给用户,并且启动异步更新机制,同时更新A和B

 

    

Jedis操作:

    在Java1.x版本中,使用的是Jedis作为Redis的操作工具,如果我们要使用Redis,就要做以下步骤:

        1. 引入POM依赖

        2. 编写JedisConfig配置类,生成JedisPool这个Bean对象,交给IOC管理

        3. 从JedisPool获取到Jedis操作实例,用于操作具体数据

        4. 如果要操作Java实体类,那么我们要把实体类实现序列化,编写序列化器,然后才能以二进制流的方式传输

 

package org.example;

 

import org.example.entity.User;

import org.example.util.SerializeUtil;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringRunner;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.Transaction;

import redis.clients.jedis.params.SetParams;

 

import java.util.HashMap;

import java.util.Map;

 

@SpringBootTest

@RunWith(SpringRunner.class)

public class Five_Type {

 

    @Autowired

    JedisPool jedisPool;

 

    Jedis jedis;

    @Before

    public void before() {

        jedis = jedisPool.getResource();

    }

 

    @After

    public void after() {

        if (jedis != null) jedis.close();

    }

 

    /**

     * 通用操作:

     * 通用删除

     * 通用查询

     * 层级目录

     * 给已存在的key设定失效时间

     * 设定一个会过期并且还未存在的key

     * 查看redis当前数据库存了多少东西

     * 查询失效时间

     */

    @Test

    public void commonOpera() {

        // 通用删除

        jedis.del("操作2.1");

        //通用查询

        jedis.keys("*").forEach(item -> {

            System.out.println(item);

        });

        //层级目录

        jedis.set("层级目录:一级目录:二级目录","value");

        //给已存在的key设定失效时间

        jedis.set("已存在的key","已存在的value");

        jedis.expire("已存在的key",15);

        //设定一个会过期并且还未存在的key

        jedis.setex("未存在的key",15,"未存在的value");

        //查看redis当前数据库存了多少东西

        System.out.println(jedis.dbSize());

        //查询失效时间

        System.out.println(jedis.ttl("已存在的key"));;

    }

 

    /**

     * String类型

     */

    @Test

    public void OperaString() {

        //添加数据

        jedis.set("操作1","单独添加");

        //批量添加数据

        jedis.mset("操作2.1","批量添加","操作2.2","批量添加");

        //获取数据

        System.out.println(jedis.get("操作1"));

        //批量获取数据 返回list

        jedis.mget("操作2.1","操作2.2").forEach(item -> {

            System.out.println(item);

        });

    }

 

    /**

     * List类型

     */

    @Test

    public void OperaList() {

        //依次左推入

        jedis.lpush("操作3","操作3.1","操作3.2");

        //依次右推入

        jedis.rpush("操作3","操作3.3","操作3.4");

        //列表查询

        jedis.lrange("操作3",0,8).forEach(i -> {

            System.out.println(i);

        });

        //列表删除

        jedis.lrem("操作3",2,"操作3.1");

    }

 

    /**

     * Hash类型

     */

    @Test

    public void OperaHash() {

        //添加数据 不需要用hmset了,hset就能批量写入

        Map<String, String> map = new HashMap<>();

        map.put("操作4.1","操作4.1=>value");

        map.put("操作4.2","操作4.2=>value");

        map.put("操作4.3","操作4.3=>value");

        jedis.hset("操作4",map);

        //删除数据

        jedis.hdel("操作4","操作4.1");

        //所有的查询操作

        jedis.hgetAll("操作4").forEach((key,value)-> {

            System.out.println(key + " " + value);

        });

        //单独查询操作

        System.out.println(jedis.hget("操作4","操作4.2"));

    }

 

    /**

     * Set类型

     */

    @Test

    public void OperaSet() {

        //添加数据

        jedis.sadd("操作5","操作5.1");

        //Set不会加入重复元素

        jedis.sadd("操作5","操作5.1");

        jedis.sadd("操作5","操作5.2","操作5.3");

        //删除操作

        jedis.srem("操作5","操作5.2");

        //查询总行数操作

        System.out.println(jedis.scard("操作5"));

        //查询成员操作

        jedis.smembers("操作5").forEach(item ->{

            System.out.println(item);

        });

    }

 

    /**

     * SortedSet类型

     */

    @Test

    public void OperaSortSet() {

        //添加数据

        jedis.zadd("操作6",10,"操作6.1");

        jedis.zadd("操作6",6,"操作6.2");

        jedis.zadd("操作6",3,"操作6.3");

        //查看行数

        System.out.println(jedis.zcard("操作6"));

        //查看成员

        jedis.zrange("操作6",0,8).forEach(item -> {

            System.out.println(item);

        });

        //删除操作

        jedis.zrem("操作6.1","操作6.2");

    }

 

    @Test

    public void OperaExpireAndExist() {

        jedis.set("过期与否","十秒过期",new SetParams().ex(10));

        jedis.set("存在与否","不存在就加入",new SetParams().nx());

    }

 

    /**

     * 操作实体类

     */

    @Test

    public void OperaPojo() {

        User user = new User(3,"张三","123456");

        jedis.set("user".getBytes(), SerializeUtil.serialize(user));

 

        User value = (User) SerializeUtil.reverse_serialize(jedis.get("user".getBytes()));

        System.out.println(value.toString());

    }

 

    /**

     * Redis事务

     * Redis事务非常弱,我们一般不会用它

     * 了解:乐观锁

     */

    @Test

    public void OperaTx() {

        Transaction tx = jedis.multi();

        tx.set("事务","事务操作",new SetParams().ex(10));

        //提交事务

        tx.exec();

        //回滚事务

        //tx.discard();

    }

}

 

 

Lettuce操作:

    在Java2.0版本之后,使用了Lettuce作为Redis的操作类,解决了Jedis线程不安全的问题,并添加了哨兵等操作,除此之外,还有其他新的操作:例如List的leftPop操作等

    1. 引入POM依赖

    2. 编写RedisTemplateConfig配置类,配置RedisTemplate并交给IOC管理,在RedisTemplate中。

如果要使用泛型<String,Object>,那么必须在 Key和HashKey传入StringRedisSerializer参数,在Value和HashValue传入GenericJackson2JsonRedisSerializer参数

    3. 如果要使用哨兵,有两种方法:

        3.1 使用application.yml配置哨兵

        3.2 编写Sentinel配置类来配置哨兵,返回一个RedisSentinelConfiguration交给IOC处理

 

package org.example;

 

import org.example.entity.User;

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.data.redis.core.*;

 

import java.util.HashSet;

import java.util.Set;

import java.util.concurrent.TimeUnit;

 

@SpringBootTest

class RedisLettuctApplicationTests {

 

    /**

     * 在 lettuce 中,我们可以创建 RedisTemplate 模板,从里面可以获取到对于各个数据类型的操作类

     * 需要为 RedisTemplate 创建泛型,防止乱码

     * 除了 RedisTemplate 之外,还有 StringRedisTemplate 等模板类

     * String类型 ==> redisTemplate.opsForValue()

     * List类型 ==> redisTemplate.opsForList()

     * Hash类型 ==> redisTemplate.opsForHash()

     * Set类型 ==> redisTemplate.opsForSet()

     * SortedSet类型 ==> redisTemplate.opsForZSet()

     *

     * 配置序列化器

     * 实现 RedisTemplateConfig 类, 对Key传入 StringRedisSerializer, key一般使用 String序列化器

     * 对Value传入 GenericJackson2JsonRedisSerializer,value一般使用 普遍序列化器

     *

     * 配置哨兵

     * 1. application.yml配置哨兵

     * 2. 实现哨兵配置类配置哨兵

     * 在实际开发中,如果我们是配置好主从了的话,如果主节点宕机了,那么lettuce将无法连接

     * ==> 当我们在lettuce配置了哨兵之后,如果主节点宕机了,lettuce会自动的去哨兵那边查找新的主节点写入数据

     */

    @Autowired

    RedisTemplate<String,Object> redisTemplate;

 

 

    /**

     * **通用操作是使用redisTemplate来操作的**

     *

     * 操作String类型(不特殊写了)

     * set ==> 单条存入

     * multiSet ==> 多条存入

     * get ==> 单条取出

     * multiGet ==> 多条取出

     * 层级目录 ==> 一样的

     * 通用删除 ==> 使用redisTemplate来操作

     *

     */

    @Test

    public void OperaString() {

        ValueOperations ops = redisTemplate.opsForValue();

        ops.set("String类型","String0.1");

        //通用操作

        redisTemplate.delete("String类型");

        System.out.println(ops.get("String类型"));

    }

 

    /**

     * 操作Hash类型

     * put ==> 单条存入

     * putAll ==> 多条存入

     * get ==> 单条取出

     * multiGet ==> 多条取出

     * entries ==> 获取一个key中的所有对象

     * delete ==> 删除key中的键值对

     */

    @Test

    public void OperaHash() {

        HashOperations ops = redisTemplate.opsForHash();

        ops.put("Hash类型","Hash0.1","Hash0.1.1");

        System.out.println(ops.get("Hash类型","Hash0.1"));

        ops.entries("Hash类型").forEach((key,value) -> {

            System.out.println(key + " " + value);

        });

    }

 

    /**

     * 操作List类型

     * (leftPush / rightPush) / (leftPop / rightPop)==> 往 左/右 推 入/出 一个元素

     * ==> 有一个三个String参数的方法,是按照成员插入数据,插入的数据放在pivot的前面或者后面

     * ==> 阻塞队列 pop里面有个timeout参数 ==> 与失效时间的timeout分开

     * leftPushAll / rightPushAll ==> 往 左/右 推入多个元素

     * remove ==> 删除

     * range ==> 获取全部数据

     * size ==> 获取数据数

     * index ==> 按照索引寻找

     */

    @Test

    public void OperaList() {

        ListOperations ops = redisTemplate.opsForList();

        ops.leftPush("List类型","Lpush01");

        ops.leftPush("List类型","Lpush02");

        ops.rightPush("List类型","Lpush03");

        ops.rightPush("List类型","Lpush04");

        System.out.println(ops.size("List类型"));

        ops.range("List类型",0,8).forEach(item -> {

            System.out.println(item);

        });

        ops.index("List类型",2);

    }

 

    /**

     * 操作Set类型

     * add ==> 可变参数,插入数据

     * size ==> 查看数据量

     * member ==> 查看全部数据

     * remove ==> 删除数据

     */

    @Test

    public void OperaSet() {

        SetOperations ops = redisTemplate.opsForSet();

        ops.add("Set类型","Set01","Set02","Set03");

        ops.size("Set类型");

        ops.members("Set类型").forEach(item-> {

            System.out.println(item);

        });

    }

 

    /**

     * 操作SortedSet类型

     * add ==> 插入数据,可以一次插入多条,但是要准备参数

     * size ==> 查看数据量

     * range ==> 查看全部数据

     * remove ==> 删除数据

     */

    @Test

    public void OperaSortedSet() {

        ZSetOperations ops = redisTemplate.opsForZSet();

        ZSetOperations.TypedTuple<Object> t1 = new DefaultTypedTuple<Object>("ZSet类型01",10D);

        ZSetOperations.TypedTuple<Object> t2 = new DefaultTypedTuple<Object>("ZSet类型02",12D);

        ZSetOperations.TypedTuple<Object> t3 = new DefaultTypedTuple<Object>("ZSet类型03",15D);

        Set<ZSetOperations.TypedTuple<Object>> set = new HashSet<>();

        set.add(t1);

        set.add(t2);

        set.add(t3);

        ops.add("ZSet类型", set);

        ops.range("ZSet类型",0,8);

        ops.remove("ZSet类型","ZSet类型02");

        ops.size("ZSet类型");

    }

 

    /**

     * 操作实体类

     *

     */

    @Test

    public void OperaEntity() {

        ValueOperations ops = redisTemplate.opsForValue();

        ops.set("user",new User(2,"root","123456"));

        User user = (User) ops.get("user");

        System.out.println(user.toString());

    }

 

    /**

     * 通用命令

     * keys

     * delete

     * 层级目录

     */

    @Test

    public void OperaCommon() {

        redisTemplate.keys("*").forEach(item -> {

            System.out.println(item);

        });

        redisTemplate.delete("");

    }

 

    /**

     * 操作失效时间

     * 设置的时候设置失效时间 set

     * 给已有的值设置失效时间 expire

     * 查询失效时间 getExpire

     *

     * Key值存在与否 ==> setIfPresent

     * ==> setIfAbsent

     */

    @Test

    public void OperaExpire() {

        //设置的时候设置失效时间

        redisTemplate.opsForValue().set("Expire","expire",20,TimeUnit.SECONDS);

        //给已有的值设置失效时间

        redisTemplate.opsForValue().set("HasKeyExpire","expire");

        redisTemplate.expire("HasKeyExpire",10,TimeUnit.SECONDS);

        //查看失效时间

        System.out.println(redisTemplate.getExpire("HasKeyExpire"));

        //Key值存在与否

        redisTemplate.opsForValue().setIfPresent("123","456");

        redisTemplate.opsForValue().setIfAbsent("123","456");

    }

}

        

 

    

posted @ 2022-03-28 17:01  Quent1nCn  阅读(71)  评论(0编辑  收藏  举报