Redis
需要笔记的可以加群,这是我自己的群,一个月了就我一个人,希望能和一群人交流学习,无论你是高手还是糕手,到了这技术要学会,🐂也要吹上天
1. Redis数据库相关指令
1.1 数据库操作指令
# 1.Redis中库说明
- 使用redis的默认配置器动redis服务后,默认会存在16个库,编号从0-15
- 可以使用select 库的编号 来选择一个redis的库
# 2.Redis中操作库的指令
- 清空当前的库 FLUSHDB
- 清空全部的库 FLUSHALL
# 3.redis客户端显示中文
- ./redis-cli -p 7000 --raw
1.2 操作key相关指令
# 1.DEL指令
- 语法 : DEL key [key ...]
- 作用 : 删除给定的一个或多个key 。不存在的key 会被忽略。
- 可用版本: >= 1.0.0
- 返回值: 被删除key 的数量。
# 2.EXISTS指令
- 语法: EXISTS key
- 作用: 检查给定key 是否存在。
- 可用版本: >= 1.0.0
- 返回值: 若key 存在,返回1 ,否则返回0。
# 3.EXPIRE
- 语法: EXPIRE key seconds
- 作用: 为给定key 设置生存时间,当key 过期时(生存时间为0 ),它会被自动删除。
- 可用版本: >= 1.0.0
- 时间复杂度: O(1)
- 返回值:设置成功返回1 。
# 4.KEYS
- 语法 : KEYS pattern
- 作用 : 查找所有符合给定模式pattern 的key 。
- 语法:
KEYS * 匹配数据库中所有key 。
KEYS h?llo 匹配hello ,hallo 和hxllo 等。
KEYS h*llo 匹配hllo 和heeeeello 等。
KEYS h[ae]llo 匹配hello 和hallo ,但不匹配hillo 。特殊符号用 "\" 隔开
- 可用版本: >= 1.0.0
- 返回值: 符合给定模式的key 列表。
# 5.MOVE
- 语法 : MOVE key db
- 作用 : 将当前数据库的key 移动到给定的数据库db 当中。
- 可用版本: >= 1.0.0
- 返回值: 移动成功返回1 ,失败则返回0 。
# 6.PEXPIRE
- 语法 : PEXPIRE key milliseconds
- 作用 : 这个命令和EXPIRE 命令的作用类似,但是它以毫秒为单位设置key 的生存时间,而不像EXPIRE 命令那样,以秒为单位。
- 可用版本: >= 2.6.0
- 时间复杂度: O(1)
- 返回值:设置成功,返回1 key 不存在或设置失败,返回0
# 7.PEXPIREAT
- 语法 : PEXPIREAT key milliseconds-timestamp
- 作用 : 这个命令和EXPIREAT 命令类似,但它以毫秒为单位设置key 的过期unix 时间戳,而不是像EXPIREAT那样,以秒为单位。
- 可用版本: >= 2.6.0
- 返回值:如果生存时间设置成功,返回1 。当key 不存在或没办法设置生存时间时,返回0 。(查看EXPIRE 命令获取更多信息)
# 8.TTL
- 语法 : TTL key
- 作用 : 以秒为单位,返回给定key 的剩余生存时间(TTL, time to live)。
- 可用版本: >= 1.0.0
- 返回值:
当key 不存在时,返回-2 。
当key 存在但没有设置剩余生存时间时,返回-1 。
否则,以秒为单位,返回key 的剩余生存时间。
- Note : 在Redis 2.8 以前,当key 不存在,或者key 没有设置剩余生存时间时,命令都返回-1 。
# 9.PTTL
- 语法 : PTTL key
- 作用 : 这个命令类似于TTL 命令,但它以毫秒为单位返回key 的剩余生存时间,而不是像TTL 命令那样,以秒为单位。
- 可用版本: >= 2.6.0
- 返回值: 当key 不存在时,返回-2 。当key 存在但没有设置剩余生存时间时,返回-1 。
- 否则,以毫秒为单位,返回key 的剩余生存时间。
- 注意 : 在Redis 2.8 以前,当key 不存在,或者key 没有设置剩余生存时间时,命令都返回-1 。
# 10.RANDOMKEY
- 语法 : RANDOMKEY
- 作用 : 从当前数据库中随机返回(不删除) 一个key 。
- 可用版本: >= 1.0.0
- 返回值:当数据库不为空时,返回一个key 。当数据库为空时,返回nil 。
# 11.RENAME
- 语法 : RENAME key newkey
- 作用 : 将key 改名为newkey 。当key 和newkey 相同,或者key 不存在时,返回一个错误。当newkey 已经存在时,RENAME 命令将覆盖旧值。
- 可用版本: >= 1.0.0
- 返回值: 改名成功时提示OK ,失败时候返回一个错误。
# 12.TYPE
- 语法 : TYPE key
- 作用 : 返回key 所储存的值的类型。
- 可用版本: >= 1.0.0
- 返回值:
none (key 不存在)
string (字符串)
list (列表)
set (集合)
zset (有序集)
hash (哈希表)
1.3 String类型
1. 内存存储模型
2. 常用操作命令
命令 | 说明 |
---|
set | 设置一个key/value | get | 根据key获得对应的value | mset | 一次设置多个key value | mget | 一次获得多个key的value | getset | 获得原始key的值,同时设置新值 | strlen | 获得对应key存储value的长度 | append | 为对应key的value追加内容 | getrange 索引0开始 | 截取value的内容 | setex | 设置一个key存活的有效期(秒) | psetex | 设置一个key存活的有效期(毫秒) | setnx | 存在不做任何操作,不存在添加 | msetnx原子操作(只要有一个存在不做任何操作) | 可以同时设置多个key,只有有一个存在都不保存 | decr | 进行数值类型的-1操作 | decrby | 根据提供的数据进行减法操作 | Incr | 进行数值类型的+1操作 | incrby | 根据提供的数据进行加法操作 | Incrbyfloat | 根据提供的数据加入浮点数 |
1.4 List类型
list 列表 相当于java中list 集合 特点 元素有序 且 可以重复
1.内存存储模型
2.常用操作指令
命令 | 说明 |
---|
lpush | 将某个值加入到一个key列表头部 | lpushx | 同lpush,但是必须要保证这个key存在 | rpush | 将某个值加入到一个key列表末尾 | rpushx | 同rpush,但是必须要保证这个key存在 | lpop | 返回和移除列表左边的第一个元素 | rpop | 返回和移除列表右边的第一个元素 | lrange | 获取某一个下标区间内的元素 | llen | 获取列表元素个数 | lset | 设置某一个指定索引的值(索引必须存在) | lindex | 获取某一个指定索引位置的元素 | lrem | 删除重复元素 | ltrim | 保留列表中特定区间内的元素 | linsert | 在某一个元素之前,之后插入新元素 |
1.5 Set类型
特点: Set类型 Set集合 元素无序 不可以重复
1.内存存储模型
2.常用命令
命令 | 说明 |
---|
sadd | 为集合添加元素 | smembers | 显示集合中所有元素 无序 | scard | 返回集合中元素的个数 | spop | 随机返回一个元素 并将元素在集合中删除 | smove | 从一个集合中向另一个集合移动元素 必须是同一种类型 | srem | 从集合中删除一个元素 | sismember | 判断一个集合中是否含有这个元素 | srandmember | 随机返回元素 | sdiff | 去掉第一个集合中其它集合含有的相同元素 | sinter | 求交集 | sunion | 求和集 |
1.6 ZSet类型
特点: 可排序的set集合 排序 不可重复
ZSET 官方 可排序SET sortSet
1.内存模型
2.常用命令
命令 | 说明 |
---|
zadd | 添加一个有序集合元素 | zcard | 返回集合的元素个数 | zrange 升序 zrevrange 降序 | 返回一个范围内的元素 | zrangebyscore | 按照分数查找一个范围内的元素 | zrank | 返回排名 | zrevrank | 倒序排名 | zscore | 显示某一个元素的分数 | zrem | 移除某一个元素 | zincrby | 给某个特定元素加分 |
7.7 hash类型
特点: value 是一个map结构 存在key value key 无序的
1.内存模型
2.常用命令
命令 | 说明 |
---|
hset | 设置一个key/value对 | hget | 获得一个key对应的value | hgetall | 获得所有的key/value对 | hdel | 删除某一个key/value对 | hexists | 判断一个key是否存在 | hkeys | 获得所有的key | hvals | 获得所有的value | hmset | 设置多个key/value | hmget | 获得多个key的value | hsetnx | 设置一个不存在的key的值 | hincrby | 为value进行加法运算 | hincrbyfloat | 为value加入浮点值 |
2.数据持久化
redis数据持久化分为两种:快照(rdb)、AOF(append only file)
当rdb和aof都开启时,redis在启动时会采用AOF来恢复数据
2.1 快照(RDB)
保存某一时刻的数据,redis默认使用的方式。它会生成.rdb后缀的文件(最后一次持久化的数据可能丢失)
生成快照文件的几种方式:
SAVE 和 BGSAVE 两个命令都会调用 rdbSave 函数,但它们调用的方式各有不同:
SAVE 直接调用 rdbSave ,阻塞 Redis 主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求。
BGSAVE 则 fork 出一个子进程,子进程负责调用 rdbSave ,并在保存完成之后向主进程发送信号,通知保存已完成。 Redis 服务器在BGSAVE 执行期间仍然可以继续处理客户端的请求。
Save是阻塞方式的;bgsave是非阻塞方式的。
- 客户端bgsave命令:调用fork创建一个子进程,子进程负责将快照写入到磁盘,主进程继续处理命令
- 客户端save命令:主进程负责快照生成,也就是说会导致redis无法对外服务,阻塞。
- 自动触发,当配置文件的条件满足时,触发快照生成:(执行bgsave命令)
- 客户端shutdown命令:执行的是save命令
2.2 AOF(append only file)
将所有的写命命令记录到日志文件
要使用AOF,需开启,在配置文件中:
日志追加频率: always、everysec、no
always:来一个写命令就追加一次(以一个写命令为单位),虽然它可以保证数据不丢失,但是大量的写操作会极大降低redis运行效率。
everysec(推荐):以1s为单位,一秒追加一次,一秒内随便来多少个写命令,1s到了把1s内的写命令全部追加。可以看到这是redis默认使用的,redis可以保证,即使系统崩溃最多只会丢失1s的数据
no:不是不追加,而是把什么时候追加交给操作系统,操作系统需要的时候刷新即可
随着redis运行时间的增加,aof文件会越来越大,就会导致恢复数据越来越慢。所以为了压缩aof文件的大小,redis提供了AOF重写机制
2.3 AOF重写的两种方式
- 客户端命令:BGREWRITEAOF(bgrewriteaof)即后台重写,不会阻塞redis服务
- 配置自动触发
这里有两个参数,解释下:
上面是一个百分比,这里是100%
下面是aof最小多少兆,这里是64
它两加起来就是这个意思:当aof文件达到64mb时,触发第一次重写,假如重写后为20mb;那么!下一次触发重写就是aof文件从20mb扩大了一倍(即100%的含义)为40mb时。你设置500%,下一次就是100mb触发重写
2.4 AOF重写原理
重写并不是在原有AOF文件的基础上进行压缩,而是将内存中的数据内容以命令的方式记录到一个临时的AOF文件中,然后将原来的替换掉,下面是我画的过程图:
首先,我们应该弄明白怎么aof文件的体积就变小了?
举个例子,比如我对key为test的value(值为0)进行incr 1 ,加一操作,执行了1000次,aof中就记录了1000条记录,其实就只需要记录一条set test 1000不就是记录了test的值了吗。
它的过程我,描述一下:首先redis收到重写aof的命令时redis会调用fork()创建一个子进程,这个子进程会生成快照,然后将快照中的数据转变为写记录 写入临时的aof文件;与此同时,因为主线程还在工作,还会有新的写命令,主线程会将写命令继续追加到原来的文件(因为害怕子进程出现问题而导致后续的数据丢失),并将其缓存起来。当临时aof文件生成后,子进程会通知主进程,让主进程把缓存的写命令追加到临时文件。最后就将原来的文件替换掉,就完成了重写
3.SpringBoot 整合Redis
Spring Boot Data Redis提供了两个模板类:RedisTemplate和StringRedisTemplate。
RedisTemplate<Object,Object>,两个泛型都是Object类型,即key、value都是对象;但是Redis库中存储的都是String,所以RedisTemplate在存储时会自动将对象序列化,在取的时候会自动反序列化,这就要求使用的对象必须实现序列化接口(implements Serializable)!!!
而StringRedisTemplate<String,String>两个泛型都是String的,StringRedisTemplate是RedsiTemplate的子类
3.1 创建springboot项目
使用快速构建,你可以勾选上:lombok、web、redis
这里也提供一下pom:
<dependencies>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3.2 编写配置
#redis地址
spring.redis.host=127.0.0.1
#redis端口号
spring.redis.port=6379
#使用哪个库
spring.redis.database=0
3.3 编写测试类(以StringRedisTemple为介绍)
我们需要注入StringRedisTemplate(它和RedisTemplate都交给了Spring容器管理)
@SpringBootTest
class RedisApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
//StringRedisTemple测试类
@Test
void redis() {
}
}
api介绍:
测试方法:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
//StringRedisTemple测试类
@Test
void redis() {
//往redis中存一个key为name,值为xiaoxiang的数据
stringRedisTemplate.opsForValue().set("name","xiaoxiang");
//取出name的值
String value = stringRedisTemplate.opsForValue().get("name");
System.out.println(value);
}
}
结果:
Redis库中也有该条数据:
对key的操作:
//对key的操作:
//删除key
stringRedisTemplate.delete("name");
//设置key过期时间
stringRedisTemplate.expire("name", 10 , TimeUnit.DAYS);
//获取过期时间
stringRedisTemplate.getExpire("name");
//获取指定key的value是什么数据类型
stringRedisTemplate.type("name");
==对String类型的操作:==不能一一介绍,大家根据api字面意思对照前面的操作命令就能知道是干啥的了,可以自己玩一玩。其它类型的数据的使用和string差不多,api不同大家可自行体会就不介绍了
//hash相关操作 opsForHash
@Test
public void testHash(){
stringRedisTemplate.opsForHash().put("maps","name","小黑");
Object o = stringRedisTemplate.opsForHash().get("maps", "name");
System.out.println(o);
}
//zset相关操作 opsForZSet
@Test
public void testZSet(){
stringRedisTemplate.opsForZSet().add("zsets","小黑",10);
Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);
zsets.forEach(value-> System.out.println(value));
}
//set相关操作 opsForSet
@Test
public void testSet(){
stringRedisTemplate.opsForSet().add("sets","xiaosan","xiaosi","xiaowu");
Set<String> sets = stringRedisTemplate.opsForSet().members("sets");
sets.forEach(value-> System.out.println(value));
}
//list相关的操作opsForList
@Test
public void testList(){
// stringRedisTemplate.opsForList().leftPushAll("lists","张三","李四","王五");
List<String> lists = stringRedisTemplate.opsForList().range("lists", 0, -1);
lists.forEach(key -> System.out.println(key));
}
//String相关的操作 opsForValue
@Test
public void testString(){
//stringRedisTemplate.opsForValue().set("166","好同学");
String s = stringRedisTemplate.opsForValue().get("166");
System.out.println(s);
Long size = stringRedisTemplate.opsForValue().size("166");
System.out.println(size);
}
//key相关的操作
@Test
public void test(){
Set<String> keys = stringRedisTemplate.keys("*");//查看所有key
Boolean name = stringRedisTemplate.hasKey("name");//判断某个key是否存在
stringRedisTemplate.delete("age");//根据指定key删除
stringRedisTemplate.rename("","");//修改key的名称
stringRedisTemplate.expire("key",10, TimeUnit.HOURS);
//设置key超时时间 参数1:设置key名 参数2:时间 参数3:时间的单位
stringRedisTemplate.move("",1);//移动key
}
如想了解更多api,请看视频:
操作key和String类型数据:https://www.bilibili.com/video/BV1jD4y1Q7tU?p=12
操作list、set、zset:https://www.bilibili.com/video/BV1jD4y1Q7tU?p=13
操作hash、RedisTemplate(重要):https://www.bilibili.com/video/BV1jD4y1Q7tU?p=14
绑定key API:https://www.bilibili.com/video/BV1jD4y1Q7tU?p=15
4.Redis应用场景
视频链接:https://www.bilibili.com/video/BV1jD4y1Q7tU?p=16
验证码存储(设置超时,时效性)、
具有时效性的业务(比如订单还有多少时间失,时效性)、
分布式集群中session共享、
利用zset类型(元素 分数),可排序,可以做排行榜之类的把商品id作为key,销量作为分数,选出排名即可。
分布式缓存
存储认证后的token(时效性)
解决分布式系统集群的分布式锁问题
持续更新中。。。。。。。。。。。。。。。。
|