redis基础

redis 简介

redis 是高性能键值对数据库,支持键值数据类型:

  • 字符串类型
  • 列表类型
  • 有序集合类
  • 散列类型
  • 集合类型

redis 的应用场景

  • 缓存
  • 任务队列
  • 应用排行榜
  • 网站访问统计
  • 数据过期处理
  • 分布式集群架构中的 session 分离

redis 五种数据类型

  • 字符串(String)
  • 哈希(hash)
  • 字符串列表(list)
  • 字符串集合(set)
  • 有序字符串集合(sorted set)

存储 String

  • 二进制安全的,存入和获取的数据相同。
  • Value 最多可以容纳的数据长度是 512M

redis 基本操作

String 类型

Hash 类型

存入键值对, 将 username:jack 存入 myhash

1
2
hset myhash username jack
hset myhash age 20

一次存入多个键值对

1
hmset myhash2 username rose age 21

根据键获取值

1
hget myhash username

返回

1
"jack"

根据多个键获取值

1
hmget myhash2 username age

返回

1
2
1) "rose"
2) "21"

获取所有键值对

1
hgetall myhash

删除某个键值对

1
hdel myhash2 username age

返回

1
2
3
4
1) "username"
2) "jack"
3) "age"
4) "20"

对某个数字进行增加:将 age 属性递增5。

1
hincrby myhash2 age 5

返回

1
(integer) 26

rose 的 age 属性由 21 增加到 26

判断某个set中是否含有某个键

1
hexists myhash username

获取 hash 中的所有键

1
hkeys myhash

运行结果为:

1
2
1) "username"
2) "age"

获取 hash 中的所有值

1
hvals myhash

运行结果为

1
2
1) "jack"
2) "20"

List 类型

list 中存储数据(从左侧添加,先进去的数据排在最后一位)

1
2
lpush mylist a b c
lpush mylist 1 2 3

从右侧添加 (从右侧添加)

1
2
rpush mylist2 a b c
rpush mylist2 a b c

查看列表 表示从第一个到第六个元素

1
lrange 0 5

运行结果如下

1
2
3
4
5
6
1) "3"
2) "2"
3) "1"
4) "c"
5) "b"
6) "a"
1
lrange mylist2 0 -1

表示从第一个到倒数第一个元素

运行结果如下

1
2
3
4
5
6
1) "a"
2) "b"
3) "c"
4) "1"
5) "2"
6) "3"

左边弹出

1
lpop mylist

运行结果

1
"3"

右边弹出

1
rpop mylist2

运行结果

1
"3"

lpushxrpushx 仅当需要操作的 list 中有值时才进行保存操作

现在 mylist3 的数据如下

1
2
3
4
5
6
7
8
9
10
11
 1) "5"
2) "3"
3) "2"
4) "3"
5) "7"
6) "6"
7) "3"
8) "5"
9) "4"
10) "2"
11) "1"

移除命令 lrem

从左侧开始删除两个3

1
lrem mylist3 2 3

运行后的 mylist3 结果

1
2
3
4
5
6
7
8
9
1) "5"
2) "2"
3) "7"
4) "6"
5) "3"
6) "5"
7) "4"
8) "2"
9) "1"

从后边往前删除两个1

1
lrem mylist3 -2 1

运行后的 mylist3 结果

1
2
3
4
5
6
7
8
1) "5"
2) "2"
3) "7"
4) "6"
5) "3"
6) "5"
7) "4"
8) "2"

删除所有2

1
lrem mylist3 0 2

运行后的 mylist3 结果

1
2
3
4
5
6
1) "5"
2) "7"
3) "6"
4) "3"
5) "5"
6) "4"

给某个指定的角标位置的元素设置值

1
lset mylist 3 haha

运行结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> lrange mylist 0 -1
1) "2"
2) "1"
3) "c"
4) "b"
5) "a"
127.0.0.1:6379> lset mylist 3 haha
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "2"
2) "1"
3) "c"
4) "haha"
5) "a"

新建一个 list

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> lrange mylist4 0 -1
1) "c"
2) "b"
3) "a"
4) "c"
5) "b"
6) "a"
7) "c"
8) "b"
9) "a"

在第一个 b 之前插入 11

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> LINSERT mylist4 before b 11
(integer) 10
127.0.0.1:6379> lrange mylist4 0 -1
1) "c"
2) "11"
3) "b"
4) "a"
5) "c"
6) "b"
7) "a"
8) "c"
9) "b"
10) "a"

在第一个 b 之后插入 22

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> LINSERT mylist4 after b 22
(integer) 11
127.0.0.1:6379> lrange mylist4 0 -1
1) "c"
2) "11"
3) "b"
4) "22"
5) "a"
6) "c"
7) "b"
8) "a"
9) "c"
10) "b"
11) "a"

创建两个 list

1
2
3
4
5
6
7
8
127.0.0.1:6379> lrange mylist5 0 -1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> lrange mylist6 0 -1
1) "3"
2) "2"
3) "1"

现在讲 mylist5 右左边弹出,从左侧压入 mylist6

rpoplpush 用于消息队列

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> RPOPLPUSH mylist5 mylist6
"a"
127.0.0.1:6379> lrange mylist5 0 -1
1) "c"
2) "b"
127.0.0.1:6379> lrange mylist6 0 -1
1) "a"
2) "3"
3) "2"
4) "1"

Set 类型

set 类型不允许出现相同的操作,set 通常用作

  1. 跟踪一些唯一性数据
  2. 用户维护数据对象之间的关联关系

创建一个 set 并添加一个元素

1
2
3
sadd myset a
sadd myset 1 2 3
sadd myset 1 2

查看所有元素发现没有重复元素

1
2
3
4
5
127.0.0.1:6379> SMEMBERS myset
1) "3"
2) "1"
3) "a"
4) "2"

查看一个元素是否存在于某个集合

1
2
3
4
127.0.0.1:6379> SISMEMBER myset a
(integer) 1
127.0.0.1:6379> SISMEMBER myset x
(integer) 0

说明 myset 中包含 a,但不包含 x

创建两个 set

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> SMEMBERS mya1
1) "b"
2) "c"
3) "a"
127.0.0.1:6379> SMEMBERS myb1
1) "2"
2) "1"
3) "c"
4) "a"

找出 mya1 中有,但是 myb1 中没有的元素

1
2
127.0.0.1:6379> sdiff mya1 myb1
1) "b"

找出 myb1 中有,但是 mya1 中没有的元素

1
2
3
127.0.0.1:6379> sdiff myb1 mya1
1) "1"
2) "2

sdiff 产生的结果直接保存

1
2
3
4
127.0.0.1:6379> SDIFFSTORE my1 mya1 myb1
(integer) 1
127.0.0.1:6379> SMEMBERS my1
1) "b"

找出 mya1 ,myb1 中都有的元素

1
2
3
127.0.0.1:6379> SINTER mya1 myb1
1) "c"
2) "a"

将上面的结果直接存储

1
2
3
4
5
127.0.0.1:6379> SINTERSTORE my2 mya1 myb1
(integer) 2
127.0.0.1:6379> SMEMBERS my2
1) "a"
2) "c"

列出 mya1myb1 的所有元素

1
2
3
4
5
6
127.0.0.1:6379> SUNION mya1 myb1
1) "b"
2) "c"
3) "2"
4) "a"
5) "1"

将上面的结果直接保存

1
2
3
4
5
6
7
8
127.0.0.1:6379> SUNIONSTORE my3 mya1 myb1
(integer) 5
127.0.0.1:6379> SMEMBERS my3
1) "b"
2) "c"
3) "2"
4) "a"
5) "1"

查看 set 中元素的个数

1
2
127.0.0.1:6379> SCARD mya1
(integer) 3

随机返回 set 中的一个元素

1
2
3
4
5
6
127.0.0.1:6379> SRANDMEMBER mya1
"b"
127.0.0.1:6379> SRANDMEMBER mya1
"a"
127.0.0.1:6379> SRANDMEMBER mya1
"c"

sorted set

sorted set 中每一个元素都有一个分数与之关联,redis 正是通过这些分数来为 set 排序,sorted set 元素是有序的.

可以用于:

  1. 大型游戏的积分排行榜
  2. 构建索引数据

添加元素

1
2
3
4
5
6
7
127.0.0.1:6379> ZADD mysort 70 zs 80 ls 90 ww
(integer) 3
// 如果 set 中已经包将要添加的元素,执行添加命令将覆盖原来的分数
127.0.0.1:6379> ZADD mysort 100 zs
(integer) 0
127.0.0.1:6379> ZADD mysort 60 tom
(integer) 1

展示元素的分数

1
2
127.0.0.1:6379> ZSCORE mysort zs
"100"

移除元素

1
2
127.0.0.1:6379> zrem mysort tom ww
(integer) 2

查看元素的个数

1
2
127.0.0.1:6379> ZCARD mysort
(integer) 2

再添加两个元素

1
2
127.0.0.1:6379> zadd mysort 85 jack 95 rose
(integer) 2

展示所有元素

1
2
3
4
5
127.0.0.1:6379> ZRANGE mysort 0 -1
1) "ls"
2) "jack"
3) "rose"
4) "zs"

展示所有元素和分数

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> ZRANGE mysort 0 -1 withscores
1) "ls"
2) "80"
3) "jack"
4) "85"
5) "rose"
6) "95"
7) "zs"
8) "100"

按分数从大到小排列

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> ZREVRANGE mysort 0 -1 withscores
1) "zs"
2) "100"
3) "rose"
4) "95"
5) "jack"
6) "85"
7) "ls"
8) "80"

删除排序从 0 到 3 的元素

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> ZRANGE mysort 0 -1
1) "bruce"
2) "perter"
3) "clark"
4) "arrow"
5) "wonder"
// 删除了排名 0 到 2 的元素
127.0.0.1:6379> ZREMRANGEBYRANK mysort 0 2
(integer) 3
127.0.0.1:6379> ZRANGE mysort 0 -1
1) "arrow"
2) "wonder"

新增几个元素

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> zrange mysort 0 -1 withscores
1) "arrow"
2) "40"
3) "wonder"
4) "50"
5) "bruce"
6) "60"
7) "clark"
8) "70"
9) "peter"
10) "80"

查找分数在 40 到 70 分区间的前两个元素

1
2
3
4
5
127.0.0.1:6379> ZRANGEBYSCORE mysort 40 70 withscores limit 0 2
1) "arrow"
2) "40"
3) "wonder"
4) "50"

增加分数

1
2
127.0.0.1:6379> ZINCRBY mysort 7 arrow
"47"

查找某个分数段内元素的个数

1
2
127.0.0.1:6379> ZCOUNT mysort 50 80
(integer) 4

redis的keys基本操作

查找所有的 keys

1
2
3
4
5
6
127.0.0.1:6379> keys *
1) "myhash2"
2) "hahaha"
3) "mylist2"
4) "myhashset2"
...

查看以 my 开头的所有的 key

1
2
3
4
127.0.0.1:6379> keys my?
1) "my3"
2) "my2"
3) "my1"

删除 keys

1
2
127.0.0.1:6379> del my1 my2 my3
(integer) 3

判断某个 key 是否存在

1
2
3
4
127.0.0.1:6379> EXISTS hahahs
(integer) 0
127.0.0.1:6379> EXISTS mysort
(integer) 1

重命名key

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> get compnay
"immooc"
127.0.0.1:6379> RENAME compnay
(error) ERR wrong number of arguments for 'rename' command
127.0.0.1:6379> RENAME compnay newcompany
OK
// 重命名之后就获取不到了
127.0.0.1:6379> get compnay
(nil)
// 使用新的名字获取
127.0.0.1:6379> get newcompany
"immooc"

设置超时时间 单位秒

1
2
3
4
5
127.0.0.1:6379> EXPIRE newcompany 1000
(integer) 1
// 查看剩余超时时间
127.0.0.1:6379> ttl newcompany
(integer) 989

查看 key 的类型

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> type newcompany
string
127.0.0.1:6379> type mylist
list
127.0.0.1:6379> type myhash
hash
127.0.0.1:6379> type mysort
zset
127.0.0.1:6379> type myset
set

redis 的事务

一个 redis 实例可以包含 15 个数据库,下标是从 0-15,默认选择第 0 号数据库

切换数据库命令如下

1
2
3
4
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
(empty list or set)

可以看到 1 号数据库中没有保存任何的key

将 0 号数据库中的一个 key 移动到 1 号数据库

1
2
3
4
5
6
127.0.0.1:6379> MOVE mysort 1
(integer) 1
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "mysort"

multi 相当于开启事务

开启事务后,输入的命令将被保存的队列中

exec 相当于 commit

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> get num
"65"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr num
QUEUED
127.0.0.1:6379> incr num
QUEUED
127.0.0.1:6379> exec
1) (integer) 66
2) (integer) 67
127.0.0.1:6379>

执行之后命令队列中的命令将会被全部执行

discard 相当于 rollerback

redis 持久化概述

redis 之所以效率很高是因为数据都保存在内存中,为了使 redis 重启之后数据不丢失,就需要将 redis 数据保存到硬盘上。

redis 持久化有两种方式:

  • RDB 方式
  • AOF 方式

持久化的使用方式

  • RDB 持久化:定期保存 redis 的快照到硬盘
  • AOF 通过日志记录 redis 的命令,每次重启之后读取这个文件来重现 redis 之前的状态
  • 无持久化:单纯将 redis 作为一个缓存服务
  • 同时使用 RDB 和 AOF

RDB 方式

redis.conf 文件中可以指定保存快照的时机

1
2
3
save 900 1
save 300 10
save 60 10000

AOF 方式

需要在 redis.conf 中打开配置

1
2
3
4
5
6
7
8
9
10
# aof 是否打开 默认是关闭的 需要改为 yes
appendonly yes
appendfilename "appendonly.aof"
# 每次操作都同步日志
# appendfsync always
# 每秒同步记录一次
appendfsync everysec
# 不同步
# appendfsync no

SringBoot Redis 重要注解

Spring-boot 引入 redis 缓存机制,首先需要在启动类上增加一个注解

1
@EnableCaching

controller 的方法上增加 @Cacheable 注解,一般用于查询接口

@Cacheable(cacheNames = "product", key = '#sellerId', condition="#sellerId.length>3", unless = "#result.getCode()!=0")

#sellerId 的写法成为 spel 表达式,获取参数 sellerId的值

sellerId 的字符长度大于 3 ,而且 除了 返回的 code!=0(也就是等于0都缓存)

当数据改变之后表用 @Cacheput 注解修改缓存,通常用于保存或者修改方法

@CachePut

要使用上面两个注解更新缓存 必须保证方法的返回值一致

如果上面两个注解的 key 不填或者为空,则key默认为方法的参数,这就会导致 key不一致的问题(即使方法的返回值一致)

可以把 cacheName 属性移到 类注解 @CacheConfig(cacheNames="product")

@CacheEvict(cacheNames = "product",key="123")

清除缓存

使用上面的缓存必须实现序列化

作者

Bruce Liu

发布于

2019-03-17

更新于

2022-11-12

许可协议

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

评论

You forgot to set the shortname for Disqus. Please set it in _config.yml.