Redis

介绍

简介

  • 官网:https://redis.io
  • 教程网站:https://redis.net.cn
  • Redis是一个基于内存的(key-value)结构数据库,也被称为结构化的NoSql数据库。
    • NoSql(Not Only Sql):泛指非关系型数据库。如:Redis、Mongodb
  • 应用场景:缓存、任务队列、消息队列、分布式锁

数据类型

Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型

  • String:普通字符串,常用
  • hash:适合存储对象
  • list:按照插入顺序排序,可以有重复元素
  • set:无序集合,没有重复元素
  • sorted set:有序集合,没有重复元素

常用命令

String

  • SET key value:设置指定key的值
  • GET key:获取指定key的值
  • SETEX key seconds value:设置指定key的值,并将key的过期时间设为seconds秒
  • SETNX key value:只有在 key不存在时设置key的值

list

Redis列表是简单的字符串列表,按照插入顺序排序

  • LPUSH key value1 [value2]:将一个或多个值插入到列表头部

  • RPUSH key value1 [value2]:将一个或多个值插入到列表尾部

  • LRANGE key start stop:获取列表指定范围内的元素

    • lrange key 0 -1:获取列表中的所有元素
  • LPOP key :移除并获取列表第一个元素

  • RPOP key:移除并获取列表最后一个元素

  • ltrim key 1 3: 保留[1,3]之间的元素,其他的删除

  • LLEN key:获取列表长度

  • BRPOP key1 [key2 ] timeout:移出并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止

set

Redis set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据

  • SADD key member1[member2]:向集合添加一个或多个成员
  • SMEMBERS key:返回集合中的所有成员
  • SISMEMBER key member1:判断成员是否在集合中
  • SCARD key:获取集合的成员数
  • SREM key member1 [member2]:移除集合中一个或多个成员
  • SINTER key1 [key2]:返回给定所有集合的交集
  • SUNION key1 [key2]:返回所有给定集合的并集
  • SDIFF key1 [key2]:返回给定所有集合的差集

sorted set

Redis sorted set有序集合是string类型元素的集合,且不允许重复的成员。每个元素都会关联一个double类型的分数(score)。redis正是通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。

  • ZADD key score1 member1 [score2 member2]:向有序集合添加一个或多个成员,或者更新已存在成员的分数
  • ZRANGE key start stop [WITHSCORES]:通过索引区间返回有序集合中指定区间内的成员
  • ZSCORE key member1:查看集合中成员的分数
  • ZRANK key member1:查看集合中成员的排名(从小到大排)
  • ZREVRANK key member1:查看集合中成员的排名(从大到小排)
  • ZINCRBY key increment member:有序集合中对指定成员的分数加上增量increment
  • ZREM key member [member …]:移除有序集合中的一个或多个成员

hash

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象

image-20231128154558438

  • HSET key field value:将哈希表key 中的字段field的值设为value
  • HGET key field:获取存储在哈希表中指定字段的值
  • HGETALL key:获取在哈希表中指定key的所有字段和值
  • HDEL key field:删除存储在哈希表中的指定字段
  • HKEYS key:获取哈希表中所有字段
  • HVALS key:获取哈希表中所有值

通用命令

  • KEYS pattern:查找所有符合给定模式( pattern)的key
  • EXISTS key:检查给定key是否存在
  • TYPE key:返回key所储存的值的类型
  • TTL key:返回给定key的剩余生存时间(TTL, time to live),以秒为单位
  • DEL key:该命令用于在key存在是删除key
  • flushall:删除所有键
  • expire key:给键设置过期时间

Redis 高级

发布订阅

  • Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。
  • Redis 客户端可以订阅任意数量的频道。
  • 当有新消息通过 PUBLISH 命令发送给频道时, 这个消息就会被发送给订阅它的客户端
  • 局限性:消息无法持久化、无法记录历史消息

订阅频道

  • subscribe channel

发布消息

  • publish channel message

消息队列Stream

  • Redis Stream 是 Redis 5.0 版本新增加的数据结构。主要用于消息队列(MQ,Message Queue)
  • Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

地理位置GEO

  • Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增。

常用命令

  • geoadd:添加地理位置的坐标。

    • GEOADD key longitude latitude member [longitude latitude member …]
  • geopos:从给定的 key 里返回所有指定名称(member)的位置(经度和纬度)

    • GEOPOS key member [member …]
  • geodist:用于返回两个给定位置之间的距离。

    • GEODIST key member1 member2 [m|km|ft|mi]
  • georadius :以给定的经纬度为中心, 返回与中心的距离不超过给定最大距离的所有位置元素。

    1
    2
    3
    4
    5
    6
    7
    GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

    WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
    WITHCOORD: 将位置元素的经度和纬度也一并返回。
    COUNT 限定返回的记录数。
    ASC: 查找结果根据距离从近到远排序。
    DESC: 查找结果根据从远到近排序。
  • georadiusbymember:以给定的位置元素为中心,返回与中心的距离不超过给定最大距离的所有位置元素。

    1
    GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

HyperLogLog

  • Redis HyperLogLog 是用来做基数统计的算法
  • 基数就是集合中唯一且不重复的元素个数,比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数为5
  • HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
  • 每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。

常用命令

  • PFADD:添加指定元素到 HyperLogLog 中。
    • PFADD key element [element …]
  • pfcount:返回给定 HyperLogLog 的基数估算值。
    • PFCOUNT key [key..]
  • pfmerge:将多个 HyperLogLog 合并为一个 HyperLogLog
    • PFCOUNT destkey sourcekey [sourcekey,,,]

事务

  • Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证
    • 在执行EXEC命令前,所有的命令都会被放入到一个队列中缓存起来,不会立即执行
    • 在执行EXEC命令后,事务开始执行,事务中任意命令执行失败,其余的命令依然被执行。
    • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
  • 一个事务从开始到执行会经历以下三个阶段:开始事务-命令入队、执行事务

事务命令

  • MULTI:开启事务
  • EXEFC:执行事务
  • DISCARD:取消事务

持久化

  • 内存存储有个问题就是关闭服务或者断电会丢失,Redis的数据也支持写到硬盘中,这个过程就叫做持久化。

redis持久化的方式

  • RDB(Redis DataBase) :在指定的时间间隔内,定时的将 redis 存储的数据生成Snapshot快照并存储到磁盘等介质上
  • AOF(Append Of File) :将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。
  • 同时允许使用两种方式,AOF的优先级更高。

RDB

  • 备份文件的名称默认为dump.rdb
  • 触发RDB备份的方式
    1. 自动备份,需配置备份规则
    2. 手动执行命令备份(save和bgsave)
      • save:save时只管保存,其他不管,全部阻塞,手动保存,不建议使用。
      • bgsave:redis会在后台异步进行快照操作,快照同时还可以响应客户端情况。

AOF

  • 开启方式:在配置文件中将appendonly no改成appendonly yes

主从复制

  • 主从复制就是将主节点(master)redis的数据同步到其他从节点(slave)redis数据库上。实现高可用

哨兵模式

  • 当主机宕机后,需要手动把一台从(slave)服务器切换为主服务器,这就需要人工干预,费时费力,还回造成一段时间内服务不可用,这种就有了哨兵模式
  • 哨兵集群。基于主从复制模式,所有的主从配置优点,它都有。
  • 主从可以切换,故障可以转移,系统可用性就更好。
  • 哨兵模式是主从模式的升级,手动到自动,更完善。

Java中的Redis

  • Redis的Java客户端很多,官方推荐的有三种:Jedis、Lettuce、Redisson
  • Spring 对Redis客户端进行了整合,提供了Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即spring-boot-starter-data-redis

Jedis(不常用)

maven坐标

1
2
3
4
5
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>

实现步骤

  1. 获取连接

    1
    Jedis jedis = new Jedis("主机名",端口号);
  2. 执行操作….

  3. 关闭连接

    1
    jedis.close();

SpringDataRedis

使用步骤

  1. 导入Spring Data Redis 的maven坐标

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
  2. 配置Redis数据源

    1
    2
    3
    4
    5
    6
    spring:
    redis:
    host: localhost
    port: 6379
    database: 0
    password: 123456
  3. 编写配置类,创建RedisTemplate对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @Configuration
    @Slf4j
    public class RedisConfiguration {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
    log.info("开始创建redis模板对象...");
    RedisTemplate redisTemplate = new RedisTemplate();
    //设置redis的连接工厂对象
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    //设置redis key的序列化器
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    return redisTemplate;
    }
    }
  4. 通过RedisTemplate对象操作Redis

    1
    2
    @Autowired
    private RedisTemplate redisTemplate;

通用操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//keys  exists  type    del

//keys(keys)
Set keys = redisTemplate.keys("*");
System.out.println(keys);

//exists(hashKey)
Boolean boolName = redisTemplate.hasKey("student");
Boolean boolZzz = redisTemplate.hasKey("zzz");
System.out.println(boolName);
System.out.println(boolZzz);

//type(type)
for (Object key : keys) {
DataType type = redisTemplate.type(key);
System.out.println(type);
}

//del(delete)
redisTemplate.delete("zset1");

操作String

1
2
3
4
5
6
7
8
9
10
11
12
13
//set   get setex   setnx
ValueOperations valueOperations = redisTemplate.opsForValue();

//set(set)
valueOperations.set("name","jybzzz");
//get(get)
String name = (String) valueOperations.get("name");
System.out.println(name);
//setex(set)
valueOperations.set("code",1234,3, TimeUnit.MINUTES);
//setnx(setIfAbsent)
valueOperations.setIfAbsent("lock",1);
valueOperations.setIfAbsent("lock",2);

操作hash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//hset  hget    hdel    hkeys   hvals
HashOperations hashOperations = redisTemplate.opsForHash();

//hset(put)
hashOperations.put("student","name","jybzzz");
hashOperations.put("student","gender","male");
hashOperations.put("student","age","22");
//hget(get)
String name = (String) hashOperations.get("student", "name");
System.out.println(name);
//hkeys(keys)
Set keys = hashOperations.keys("student");
System.out.println(keys);
//hvals(values)
List values = hashOperations.values("student");
System.out.println(values);
//del(delete)
hashOperations.delete("student","age");

操作list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//lpush lrange  rpop    llen
ListOperations listOperations = redisTemplate.opsForList();

//lpush(leftPushAll、lefPush)
listOperations.leftPushAll("mylist","a","b","c");
listOperations.leftPush("mylist","d");
//lrange(range)
List mylist = listOperations.range("mylist", 0, -1);
System.out.println(mylist);
//rpop(rightPop)
listOperations.rightPop("mylist");
//llen(size)
Long size = listOperations.size("mylist");
System.out.println(size);

操作set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//sadd smembers scard sinter sunion srem
SetOperations setOperations = redisTemplate.opsForSet();

//sadd(add)
setOperations.add("set1","a","b","c","d");
setOperations.add("set2","a","b","x","y");
//smembers(members)
Set set1 = setOperations.members("set1");
System.out.println(set1);
//scard(size)
Long size = setOperations.size("set1");
System.out.println(size);
//sinter(intersect)
Set intersect = setOperations.intersect("set1", "set2");
System.out.println(intersect);
//sunion(union)
Set union = setOperations.union("set1", "set2");
System.out.println(union);
//srem(remove)
setOperations.remove("set1","a","b");

操作sorted set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//zadd zrange zincrby zrem
ZSetOperations zSetOperations = redisTemplate.opsForZSet();

//zadd(add)
zSetOperations.add("zset1","a",10);
zSetOperations.add("zset1","b",12);
zSetOperations.add("zset1","c",9);
//zrange(range)
Set zset1 = zSetOperations.range("zset1", 0, -1);
System.out.println(zset1);
//zincrby(Score)
zSetOperations.incrementScore("zset1","c",10);
//zrem(remoce)
zSetOperations.remove("zset1","a","b");

SpringCache

介绍

  • spring cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
  • spring Cache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。
  • CacheManager是Spring提供的各种缓存技术抽象接口。
  • 针对不同的缓存技术需要实现不同的CacheManager
CacheManager 描述
EhCacheCacheManager 使用EhCache作为缓存技术
GuavaCacheManager 使用Google的GuavaCache作为缓存技术
RedisCacheManager 使用Redis作为缓存技术

常用注解

注解 说明
@EnableCaching 开启缓存注解功能(放在启动类上)
@Cacheable 在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
@CachePut 将方法的返回值放到缓存中
@CacheEvict 将一条或多条数据从缓存中删除

CachePut(cacheName=xxx,key=xxx)

  • 将方法返回值放入缓存

  • 常见属性

    • cacheName:缓存的名称,每个缓存名称下面可以有多个key

    • key:缓存的key

CacheEvict

  • 将一条或多条数据从缓存中删除
  • 属性值
    • cacheName:缓存的名称
    • key:缓存的key
    • allEntries:是否删除该缓存名称下的所有缓存

Cacheable(cacheName=xxx,key=xxx,condition=xxx或unless)

  • 在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中

  • 属性值

    • cacheName:缓存的名称,每个缓存名称下面可以有多个key
    • key:缓存的key
    • condition:缓存条件缓存
    • unless:满足条件不缓存

SpEL表达式

  • Spring Expression Language

  • 常用在SpringCache中各种注解的key获取。常见写法

    • #方法返回值.xxx(推荐)
    • #p0.xxx
      • 0表示方法中的第一个参数,以此类推
    • #result.xxx
    • #root.args[0].xxx
      • 0表示方法中的第一个参数,以此类推

使用Redis作用缓存

  • 该框架的底层是基于Map实现的,当服务关闭之后缓存就不存在了。所以要改成redis缓存

坐标

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

application配置

1
2
3
4
5
6
7
8
9
spring
redis:
host: localhost
port: 6379
database: 0
password: 123456
cache:
redis:
time-to-live: 1800000 #设置缓存过期时间