redis安装使用

redis使用

本文记录学习redis学习的相关内容

文章目录

  • redis使用
  • 一、下载安装
    • 1.下载
    • 2.安装
  • 二、启动运行
    • 1.前台启动
    • 2.后台启动
  • 三、基本数据类型
    • 1.redis-key命令
    • 2.字符串String
    • 2.列表List
    • 3.集合Set
    • 4.哈希Hash
    • 5.有序集合Zset
  • 四、三种特殊数据类型
  • 五、事务
    • 1.redis没有事务隔离级别的概念
    • 2.redis不保证原子性
    • 3.redis事务的三个阶段
    • 4.示例
  • 六、持久化-RDB
    • 1.工作原理
    • 2.触发机制
    • 3.优缺点
  • 七、持久化-AOF
    • 1.工作原理
    • 2.优缺点
  • 八、Redis发布订阅(基本不用)
  • 九、Redis主从复制
  • 十、Redis哨兵模式
  • 十一、缓存穿透与雪崩
    • 1.缓存穿透(查不到)
    • 2.缓存击穿(量太大,缓存过期)
    • 3.缓存雪崩


一、下载安装

1.下载

直接去http://www.redis.cn/
这里以redis-5.0.7.tar.gz为例
下载完成后上传到/usr目录下

2.安装

进入/usr目录
解压

[root@VM-0-2-centos usr]# tar -zxvf redis-5.0.7.tar.gz -C /usr/

移动到local目录下并改下名字

[root@VM-0-2-centos usr]# mv redis-5.0.7 /usr/local/redis

进入/usr/local/redis目录下执行安装命令
因为redis是c语言编写的,在此步骤之前需要下载gcc编译器

yum install gcc-c++

如果已经安装过了直接执行如下命名

[root@VM-0-2-centos redis]# make
#然后
[root@VM-0-2-centos redis]# make install

redis默认安装到/usr/local/bin目录下
移动到/usr/local/redis

[root@VM-0-2-centos local]# mv bin/ redis/

二、启动运行

1.前台启动

进入/usr/local/redis/bin目录下
执行

[root@VM-0-2-centos bin]# ./redis-server

redis安装使用_第1张图片
重新开一个页面输入如下命令
查看6379存活即为启动成功在这里插入图片描述
如果想关闭redis
在图1界面Ctrl+C即可
[外链图片转存中…(img-rxV9GE0q-16124304165659416.png)
如此即为退出成功

以特定的配置文件启动

[root@VM-0-2-centos redis]# ./bin/redis-server redis.conf

正常我们在学习工作时候 要把配置文件备份一下 养成良好习惯

[root@VM-0-2-centos redis]# cp redis.conf redis.conf.bak

2.后台启动

vim打开编辑redis.conf

[root@VM-0-2-centos redis]# vim redis.conf

找到daemonize配置改为yes

redis安装使用_第2张图片

# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize yes

保存退出
执行启动命令

[root@VM-0-2-centos redis]# ./bin/redis-server redis.conf
25528:C 04 Feb 2021 17:22:28.557 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
25528:C 04 Feb 2021 17:22:28.557 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=25528, just started
25528:C 04 Feb 2021 17:22:28.557 # Configuration loaded

查看启动正常
在这里插入图片描述
本机连接redis
输入KEYS *(此时redis中并无数据,所以返回empty)

[root@VM-0-2-centos redis]# ./bin/redis-cli -p 6379
127.0.0.1:6379> KEYS *
(empty list or set)

三、基本数据类型

redis是一个基于内存亦可持久化(日志文件)、key-value的数据库。
它支持存储得value类型更多,字符串String、链表list、集合set、有序集合zSet、哈希类型hash

1.redis-key命令

查看当前库所有key

127.0.0.1:6379> KEYS *
(empty list or set)

设置key

127.0.0.1:6379> SET name zhangchi
OK
127.0.0.1:6379> KEYS *
2) "name"

移动数据到指定数据库

127.0.0.1:6379> MOVE name 1 //移动数据到指定数据库 1是数据库索引
(integer) 1 //受影响行数
127.0.0.1:6379> KEYS * 
(empty list or set) //数据库0中不存在name这个key
127.0.0.1:6379> SELECT 1 //切换到数据库1
OK
127.0.0.1:6379[1]> KEYS * 
1) "name" //此时数据已经被移动过来了

判断当前库是否存在某个key

127.0.0.1:6379[1]> SELECT 0
OK
127.0.0.1:6379> EXISTS name
(integer) 0 //没有返回0(也可理解为满足条件个数)
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> EXISTS name
(integer) 1 //有返回1(也可理解为满足条件个数)
127.0.0.1:6379[1]> 

删除数据

127.0.0.1:6379[1]> DEL name
(integer) 1 //存在数据被删除返回1(也可理解为满足条件个数)
127.0.0.1:6379[1]> DEL name
(integer) 0 //删除不存在数据返回0(也可理解为满足条件个数)

设置key失效时间

--方式1--
127.0.0.1:6379> SET name zhangchi 
OK
127.0.0.1:6379> EXPIRE name 20 //设置失效时间为20秒
(integer) 1
127.0.0.1:6379> ttl name //查询剩余失效时间
(integer) 18
127.0.0.1:6379> ttl name
(integer) 15
127.0.0.1:6379> ttl name
(integer) 7
127.0.0.1:6379> ttl name
(integer) -2 //-2表示已经失效了

127.0.0.1:6379> SET name zhangchi
OK
127.0.0.1:6379> ttl name
(integer) -1 //返回-1表示未设置失效时间(永不失效)

--方式2--
127.0.0.1:6379> EXPIREAT name 1612496655 //允许以时间戳的形式设置
(integer) 1
127.0.0.1:6379> ttl name
(integer) 71
127.0.0.1:6379> ttl name
(integer) 70
--注意:此方式设置的时间戳如果小于当前时间会直接失效 不会报错--

查看key对应的value数据类型

127.0.0.1:6379> SET name zhangchi
OK
127.0.0.1:6379> TYPE name
string //有key结果的话返回数据类型
127.0.0.1:6379> TYPE name0
none //无key的话返回none

重命名key

--RENAME--
127.0.0.1:6379> RENAME name nm
OK
127.0.0.1:6379> KEYS *
1) "nm"
127.0.0.1:6379> RENAME name nm
(error) ERR no such key //没有key则报错

2.字符串String

追加字符串

127.0.0.1:6379> SET name zhangchi
OK
127.0.0.1:6379> APPEND name 123
(integer) 11 //返回的是新字符串长度
127.0.0.1:6379> GET name
"zhangchi123"

指定的key对应的value加一减一(可以用于做阅读量记录)

127.0.0.1:6379> DECR name //不是数字类型挥着越界了 会报错
(error) ERR value is not an integer or out of range
127.0.0.1:6379> SET age 27
OK
127.0.0.1:6379> DECR age //减1
(integer) 26
127.0.0.1:6379> INCR age //加1
(integer) 27

指定的key对应的value加n减n

127.0.0.1:6379> DECRBY age 5 //减5
(integer) 22
127.0.0.1:6379> INCRBY age 5 //加5
(integer) 27

为数值加上浮点型数值

127.0.0.1:6379> INCRBYFLOAT age 0.5 //没有DECRBYFLOAT语句
"27.5"

获取字符串长度

127.0.0.1:6379> STRLEN name (String length缩写)
(integer) 11

截取字符串的(左闭右闭)

127.0.0.1:6379> GETRANGE name 0 7
"zhangchi" //正常获取
127.0.0.1:6379> GETRANGE name 0 15
"zhangchi123" //如果右边超过了长度不会报错,按最大值取
127.0.0.1:6379> GETRANGE name 16 15
"" //这样也不会报错
127.0.0.1:6379> GETRANGE name -16 15
"zhangchi123" //同理 这样写也没问题

用指定的value 替换key中 offset开始的值

127.0.0.1:6379> GET name
"zhangchi000"
127.0.0.1:6379> SETRANGE name 0 ZhangChi
(integer) 11 //下标从0开始逐个替换
127.0.0.1:6379> GET name
"ZhangChi000"
127.0.0.1:6379> SETRANGE name 15 ZhangChi
(integer) 23
127.0.0.1:6379> GET name
"ZhangChi000\x00\x00\x00\x00ZhangChi" //替换的字符串右边越界了的话 会自动补充null
127.0.0.1:6379> SETRANGE name -15 ZhangChi
(error) ERR offset is out of range //左边越界了会报错

设置key为新值,并返回老值

127.0.0.1:6379> GET name
"ZhangChi000\x00\x00\x00\x00ZhangChi"
127.0.0.1:6379> GETSET name zhangchi
"ZhangChi000\x00\x00\x00\x00ZhangChi"
127.0.0.1:6379> GET name
"zhangchi"

仅当key不存在时set(SET if Not eXists)

127.0.0.1:6379> KEYS *
1) "age"
2) "name"
127.0.0.1:6379> SETNX age 22
(integer) 0 //key存在不会更新
127.0.0.1:6379> GET age
"28"
127.0.0.1:6379> SETNX gender 男
(integer) 1 //key不存在不会设置
127.0.0.1:6379> GET gender
"\xe7\x94\xb7"

set 键值对并设置过期时间

127.0.0.1:6379> SETEX age 20 18
OK
127.0.0.1:6379> GET age
"18"
127.0.0.1:6379> ttl age
(integer) 8
127.0.0.1:6379> ttl age
(integer) 5
127.0.0.1:6379> ttl age
(integer) -2
127.0.0.1:6379> GET age
(nil)

批量设置key-value

127.0.0.1:6379> FLUSHALL //清空所有缓存
OK
127.0.0.1:6379> MSET name zhangchi age 18
OK
127.0.0.1:6379> KEYS *
1) "age"
2) "name"

批量设置键值对,仅当所有key都不存在成功

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MSET name zhangchi age 18
OK
127.0.0.1:6379> MSETNX name zhangchi gender 男
(integer) 0
127.0.0.1:6379> KEYS *
1) "age"
2) "name"

批量获取多个key保存的值

127.0.0.1:6379> MGET name age
1) "zhangchi"
2) "18"

以毫秒为单位set键值对失效时间

127.0.0.1:6379> PSETEX name 20000 zhangchi
OK
127.0.0.1:6379> ttl name
(integer) 14
127.0.0.1:6379> ttl name
(integer) -2

2.列表List

redis中链表底层的实现是数据结构中的双向链表,所以可以对该数据结构做限制操作,实现队列、栈。
因为是双端操作,所以列表的操作命令一般都是Rxxx或者Lxxx形式的。
可以用于
消息队列(LPUSH RPOP)
栈(LPUSH LPOP)

插入数据(左右)

127.0.0.1:6379> LPUSH name zhangchi001 zhangchi002 zhangchi003 //左插(可以批量)
(integer) 3
127.0.0.1:6379> LRANGE name 0 -1 //查询全部
1) "zhangchi003"
2) "zhangchi002"
3) "zhangchi001"
127.0.0.1:6379> RPUSH name zhangchi000 //右插(可以批量)
(integer) 4
127.0.0.1:6379> LRANGE name 0 -1 //获取全部数据
1) "zhangchi003"
2) "zhangchi002"
3) "zhangchi001"
4) "zhangchi000"

查询数据

127.0.0.1:6379> LRANGE name 0 -1 //查询所有 -1倒数第n个元素的下标
1) "zhangchi004"
2) "zhangchi003"
3) "zhangchi002"
4) "zhangchi001"
5) "zhangchi000"
127.0.0.1:6379> LRANGE name 0 2 //0-2闭区间
1) "zhangchi004"
2) "zhangchi003"
3) "zhangchi002"
127.0.0.1:6379> LRANGE name 0 15 //
1) "zhangchi004"
2) "zhangchi003"
3) "zhangchi002"
4) "zhangchi001"
5) "zhangchi000"
127.0.0.1:6379> LRANGE name -1 15
1) "zhangchi000"
127.0.0.1:6379> LRANGE name -1 1
(empty list or set)
127.0.0.1:6379> LRANGE name -1 4
1) "zhangchi000"
127.0.0.1:6379> LRANGE name -1 -1
1) "zhangchi000"
127.0.0.1:6379> LRANGE name -2 -1 //倒数第2个到倒数第1个
1) "zhangchi001"
2) "zhangchi000"

向存在的key中push值

127.0.0.1:6379> LPUSHX name zhangchi 005
(integer) 7 //存在返回元素个数
127.0.0.1:6379> LPUSHX names zhangchi 005
(integer) 0 //不存在返回0
127.0.0.1:6379> LRANGE name 0 -1
1) "005"
2) "zhangchi"
3) "zhangchi004"
4) "zhangchi003"
5) "zhangchi002"
6) "zhangchi001"
7) "zhangchi000"
127.0.0.1:6379> LRANGE names 0 -1
(empty list or set)

列表指定元素前后插入

127.0.0.1:6379> LINSERT name BEFORE 0 000
(integer) -1 //插入到没有的元素附近返回-1
127.0.0.1:6379> LRANGE name 0 -1
1) "005"
2) "zhangchi"
3) "zhangchi004"
4) "zhangchi003"
5) "zhangchi002"
6) "zhangchi001"
7) "zhangchi000"
127.0.0.1:6379> LINSERT name BEFORE 005 000
(integer) 8 //插入005前面000
127.0.0.1:6379> LINSERT name AFTER 005 000
(integer) 9 //插入005后面000
127.0.0.1:6379> LINSERT name AFTER 005 000
(integer) 10 //插入005后面000
127.0.0.1:6379> LINSERT name AFTER 000 0000
(integer) 11 //插入000前面0000(多个的话 以第一个为准)
127.0.0.1:6379> LRANGE name 0 -1
 1) "000"
 2) "0000"
 3) "005"
 4) "000"
 5) "000"
 6) "zhangchi"
 7) "zhangchi004"
 8) "zhangchi003"
 9) "zhangchi002"
10) "zhangchi001"
11) "zhangchi000"

查看列表长度

127.0.0.1:6379> LLEN name
(integer) 11 //列表存在返回长度
127.0.0.1:6379> LLEN names
(integer) 0 //不存在返回0

通过索引获取元素值

127.0.0.1:6379> LLEN names
(integer) 0
127.0.0.1:6379> LINDEX name 0
"000"
127.0.0.1:6379> LINDEX names 0
(nil) //没有返回nil

通过索引设置元素值

127.0.0.1:6379> LSET name 0 123456
OK
127.0.0.1:6379> LRANGE name 0 -1
 1) "123456"
 2) "0000"
 3) "005"
 4) "000"
 5) "000"
 6) "zhangchi"
 7) "zhangchi004"
 8) "zhangchi003"
 9) "zhangchi002"
10) "zhangchi001"
11) "zhangchi000"

删除元素并返回删除的值

127.0.0.1:6379> LRANGE name 0 -1
 1) "123456"
 2) "0000"
 3) "005"
 4) "000"
 5) "000"
 6) "zhangchi"
 7) "zhangchi004"
 8) "zhangchi003"
 9) "zhangchi002"
10) "zhangchi001"
11) "zhangchi000"
127.0.0.1:6379> LPOP name //左边删除
"123456"
127.0.0.1:6379> LRANGE name 0 -1
 1) "0000"
 2) "005"
 3) "000"
 4) "000"
 5) "zhangchi"
 6) "zhangchi004"
 7) "zhangchi003"
 8) "zhangchi002"
 9) "zhangchi001"
10) "zhangchi000"
127.0.0.1:6379> RPOP name //右边删除
"zhangchi000"
127.0.0.1:6379> LRANGE name 0 -1
1) "0000"
2) "005"
3) "000"
4) "000"
5) "zhangchi"
6) "zhangchi004"
7) "zhangchi003"
8) "zhangchi002"
9) "zhangchi001"

将一个列表的尾删除加入到另一个列表的头

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> LPUSH names zhangchi001 zhangchi002
(integer) 2
127.0.0.1:6379> LPUSH age 18 192
(integer) 2
127.0.0.1:6379> RPOPLPUSH names age
"zhangchi001" //返回被移动的元素
127.0.0.1:6379> LRANGE names 0 -1
1) "zhangchi002"
127.0.0.1:6379> LRANGE age 0 -1
1) "zhangchi001"
2) "192"
3) "18"

通过下标截取指定范围的列表

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> LPUSH names zhangchi001 zhangchi002 zhangchi003
(integer) 3
127.0.0.1:6379> LRANGE names 0 -1
1) "zhangchi003"
2) "zhangchi002"

从前(后或者所有)删除指定个数元素

127.0.0.1:6379> LPUSH age 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
(integer) 15
127.0.0.1:6379> LRANGE age 0 -1
 1) "5"
 2) "4"
 3) "3"
 4) "2"
 5) "1"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"
11) "5"
12) "4"
13) "3"
14) "2"
15) "1"
127.0.0.1:6379> LREM age 1 4 //从前面开始删除1个4
(integer) 1
127.0.0.1:6379> LRANGE age 0 -1
 1) "5"
 2) "3"
 3) "2"
 4) "1"
 5) "5"
 6) "4"
 7) "3"
 8) "2"
 9) "1"
10) "5"
11) "4"
12) "3"
13) "2"
14) "1"
127.0.0.1:6379> LREM age -2 5 //从后面开始删除2个5
(integer) 2
127.0.0.1:6379> LRANGE age 0 -1
 1) "5"
 2) "3"
 3) "2"
 4) "1"
 5) "4"
 6) "3"
 7) "2"
 8) "1"
 9) "4"
10) "3"
11) "2"
12) "1"
127.0.0.1:6379> LREM age 0 1 //删除所有1
(integer) 3
127.0.0.1:6379> LRANGE age 0 -1
1) "5"
2) "3"
3) "2"
4) "4"
5) "3"
6) "2"
7) "4"
8) "3"
9) "2"

移除列表第一个值,如果没有的话等带一定时间后返回nil

127.0.0.1:6379> BLPOP age 100 //移除第一个元素,如果没数据则等100秒后返回nil
//新开一个窗口
127.0.0.1:6379> LPUSH age 1
(integer) 1
//此时第一个窗口打印如下
1) "age"
2) "1"

127.0.0.1:6379> BRPOP age 10 //移除最后一个元素,如果没数据则等100秒后返回nil
(nil)
(10.02s)

移动列表最后一个值到另一个列表头,如果没有的话等带一定时间后返回nil

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> BRPOPLPUSH age ageext 100 //将age最后一个元素移动到ageext头并返回移动的元素 超过100秒返回nil
//新开一个窗口
127.0.0.1:6379> LPUSH age 1
(integer) 1
//原来窗口返回如下信息
"1" 
(2.99s)
127.0.0.1:6379> LRANGE age 0 -1
(empty list or set)
127.0.0.1:6379> LRANGE ageext 0 -1
1) "1"

3.集合Set

redis的set集合是String类型的无需集合,底层使用的是hash表实现的,值唯一。
最大容量2^32-1
命令都以S开头

添加一个、多个成员

127.0.0.1:6379> SADD names zhangchi001 zhangchi002
(integer) 2 //返回集合元素个数
127.0.0.1:6379> SMEMBERS names //遍历元素
1) "zhangchi001"
2) "zhangchi002"

获取集合的成员数量

127.0.0.1:6379> SCARD names
(integer) 2

返回集合中所有的成员

127.0.0.1:6379> smembers names
1) "zhangchi001"
2) "zhangchi002"

查询set中是否包含某个元素

127.0.0.1:6379> SISMEMBER names zhangchi001
(integer) 1 //有的话返回条数
127.0.0.1:6379> SISMEMBER names zhangchi
(integer) 0 //没有返回0

随机返回集合中n个元素

127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004 zc005 zc006 zc007
(integer) 7
127.0.0.1:6379> SRANDMEMBER names 4 //随机返回names中4个元素
1) "zc002"
2) "zc001"
3) "zc007"
4) "zc006"
127.0.0.1:6379> SRANDMEMBER names //不指定个数的话 就是一条
"zc002"

随机删除n个元素并返回被删除元素

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004 zc005 zc006 zc007
(integer) 7
127.0.0.1:6379> SPOP names 2 //从names中随机删除两个元素并返回
1) "zc004"
2) "zc005"
127.0.0.1:6379> SMEMBERS names
1) "zc003"
2) "zc001"
3) "zc002"
4) "zc007"
5) "zc006"
127.0.0.1:6379> SPOP names //不指定被删除个数则默认1条
"zc006"
127.0.0.1:6379> SMEMBERS names
1) "zc003"
2) "zc001"
3) "zc002"
4) "zc007"

将元素从A集合移动到B集合

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD names zc001 zc002
(integer) 2
127.0.0.1:6379> SMOVE names nms zc001
(integer) 1
127.0.0.1:6379> SMEMBERS names
1) "zc002"
127.0.0.1:6379> SMEMBERS nms
1) "zc001"

删除集合一个或多个元素

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004 zc005 zc006 zc007
(integer) 7
127.0.0.1:6379> SREM names zc001 zc002
(integer) 2 //返回被删除的个数
127.0.0.1:6379> SMEMBERS names
1) "zc005"
2) "zc003"
3) "zc007"
4) "zc004"
5) "zc006"

返回集合A相对于集合B、C、D…的并集的差集
A-B-C-D

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004
(integer) 4
127.0.0.1:6379> SADD nms zc004 zc005 zc006 zc007
(integer) 4
127.0.0.1:6379> SDIFF names nms //names-nms
1) "zc003"
2) "zc001"
3) "zc002"
127.0.0.1:6379> SADD ns zc000 zc001 zc002 zc005
(integer) 4
127.0.0.1:6379> SDIFF names nms ns //names-nms-ns
1) "zc003"

返回集合A相对于集合B、C、D…的并集的差集,并把结果赋值给新的结合O
O=A-B-C-D

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004
(integer) 4
127.0.0.1:6379> SADD nms zc004 zc005 zc006 zc007
(integer) 4
127.0.0.1:6379> SADD ns zc000 zc001 zc002 zc005
(integer) 4
127.0.0.1:6379> SDIFFSTORE newnames names nms ns
(integer) 1
127.0.0.1:6379> SMEMBERS newnames
1) "zc003"

返回所有集合交集
A∩B∩C…

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004
(integer) 4
127.0.0.1:6379>  SADD nms zc004 zc005 zc006 zc007
(integer) 4
127.0.0.1:6379> SINTER names nms
1) "zc004"

返回所有集合交集,并保存到新的集合中O
O = A∩B∩C…

127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004
(integer) 4
127.0.0.1:6379>  SADD nms zc004 zc005 zc006 zc007
(integer) 4
127.0.0.1:6379> SINTERSTORE newnames names nms
(integer) 1
127.0.0.1:6379> SMEMBERS newnames
1) "zc004"

返回所有集合并集
A∪B∪C…

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004
(integer) 4
127.0.0.1:6379> SADD nms zc004 zc005 zc006 zc007
(integer) 4
127.0.0.1:6379> SADD ns zc000 zc001 zc002 zc005
(integer) 4
127.0.0.1:6379> SUNION names nms ns
1) "zc003"
2) "zc007"
3) "zc002"
4) "zc001"
5) "zc004"
6) "zc000"
7) "zc006"
8) "zc005"

返回所有集合并集,并保存为新值
O = A∪B∪C…

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD names zc001 zc002 zc003 zc004
(integer) 4
127.0.0.1:6379>  SADD nms zc004 zc005 zc006 zc007
(integer) 4
127.0.0.1:6379> SADD ns zc000 zc001 zc002 zc005
(integer) 4
127.0.0.1:6379> SUNIONSTORE newnames names nms ns
(integer) 8
127.0.0.1:6379> SMEMBERS newnames
1) "zc003"
2) "zc007"
3) "zc002"
4) "zc001"
5) "zc004"
6) "zc000"
7) "zc006"
8) "zc005"

每次部分遍历集合元素

127.0.0.1:6379> SADD names zc001 zc002 zc003 zhangchi001 zhangchi002 zhangchi003
(integer) 6
//从names中游标为0的地方开始每次查两条
//在其中找到满足zc*通配的记录
127.0.0.1:6379> SSCAN names 0 match zc* count 2
1) "1" //返回游标的位置
2) 1) "zc003"
//第二次继续使用上次返回的游标位置查询
127.0.0.1:6379> SSCAN names 1  match zc* count 2
1) "0" //返回0则遍历结束
2) 1) "zc002"
   2) "zc001"

4.哈希Hash

redis hash是一个String类型的键值对的映射表,hash特别适合用于存储对象。

设置哈希表key(可以多个)中的字段值为value,可以覆盖
HMSET用法和HSET完全一样,HSET也可以设置多个值

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> HSET people name zhangchi age 18 //可以批量设置
(integer) 2
127.0.0.1:6379> HGETALL people //遍历key中所有值
1) "name"
2) "zhangchi"
3) "age"
4) "18"
127.0.0.1:6379> HSET people name zhangchi001 //重复设置会覆盖
(integer) 0
127.0.0.1:6379> HGETALL people
1) "name"
2) "zhangchi001"
3) "age"
4) "18"

只有当字段不存在时、设置hash表的值

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> HSET people name zhangchi
(integer) 1
//设置已经存在的字段 会失败返回0
127.0.0.1:6379> HSETNX people name zhangchi001
(integer) 0
127.0.0.1:6379> HSETNX people age 18
(integer) 1
127.0.0.1:6379> HGETALL people
1) "name"
2) "zhangchi"
3) "age"
4) "18"

查看哈希表key中是否包含某个字段

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> HSET people name zhangchi age 18
(integer) 2
127.0.0.1:6379> HEXISTS people name
(integer) 1
127.0.0.1:6379> HEXISTS people gender
(integer) 0

获取哈希表中指定字段的值

127.0.0.1:6379> HGET people name
"zhangchi"
127.0.0.1:6379> HGET people gender
(nil) //不存在的话返回nil

获取多个指定字段的值

127.0.0.1:6379> HMGET people name gender age
1) "zhangchi"
2) (nil)
3) "18"

获取在哈希表key中所有的的字段和值

127.0.0.1:6379> HGETALL people
1) "name"
2) "zhangchi"
3) "age"
4) "18"

获取哈希表中字段的数量

127.0.0.1:6379> HLEN people
(integer) 2

获取哈希表key中所有字段

127.0.0.1:6379> HKEYS people
1) "name"
2) "age"

获取hash表中所有的值

127.0.0.1:6379> HVALS people
1) "zhangchi"
2) "18"

删除多个字段

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> HMSET people name zhangchi age 18 gender man
OK
127.0.0.1:6379> HDEL people age gender
(integer) 2
127.0.0.1:6379> HGETALL people
1) "name"
2) "zhangchi"

为哈希表某个字段进行增量(整数)并返回结果

127.0.0.1:6379> HSET people name zhangchi age 18
(integer) 2
127.0.0.1:6379> HINCRBY people age 2
(integer) 20 //返回增量完成的结果
127.0.0.1:6379> HGETALL people
1) "name"
2) "zhangchi"
3) "age"
4) "20"

为哈希表某个字段进行增量(小数)并返回结果

127.0.0.1:6379> HSET people name zhangchi account 200.05
(integer) 2
127.0.0.1:6379> HINCRBYFLOAT people account 0.5
"200.55" //返回增量完成的结果
127.0.0.1:6379> HGETALL people
1) "name"
2) "zhangchi"
3) "account"
4) "200.55"

由上面的操作可以看出hash更适合存储对象,String适合存储字符串。

5.有序集合Zset

Zset和Set都是key-value都是String类型的字符串,不同点在于每个元素都有一个double类型的分数score关联,通过这个分数去排序。(集合元素是唯一的,但分数可以重复)

添加元素

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name zhangchi001 0.1 zhangchi002 0.2

获取集合成员数

127.0.0.1:6379> ZCARD name
(integer) 2

获取指定分数区间范围内集合数量

127.0.0.1:6379> ZCOUNT name 0 0.1
(integer) 1
127.0.0.1:6379> ZCOUNT name 0 0.2
(integer) 2

对指定成员的分数加上增量n

//zhangchi001分数score上新增0.1个分量
127.0.0.1:6379> ZINCRBY name 0.1 zhangchi001
"0.20000000000000001" 	//因为精度损失问题

返回有序集合中成员的分数值score

127.0.0.1:6379> ZSCORE name zhangchi001
"0.20000000000000001"

返回有序集合中指定元素的索引(下标)

127.0.0.1:6379> ZRANK name zhangchi001
(integer) 0
127.0.0.1:6379> ZRANK name zhangchi002
(integer) 1

通过索引返回指定取件范围内成员

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004
(integer) 4
127.0.0.1:6379> ZRANGE name 0 -1// -1是倒数第一的意思
1) "zc001"
2) "zc002"
3) "zc003"
4) "zc004"
127.0.0.1:6379> ZRANGE name 0 2 //下标0-2
1) "zc001"
2) "zc002"
3) "zc003"

通过字典取件进行返回
ZRANGEBYLEX key min max [LIMIT offset count]

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
//大于zc002 小于zc005 从下标为2开始取2条
127.0.0.1:6379> ZRANGEBYLEX name [zc002 [zc005 LIMIT 1 2
1) "zc003"
2) "zc004"
// - +表示最小和最大值
127.0.0.1:6379> ZRANGEBYLEX name - +  LIMIT 1 2
1) "zc002"
2) "zc003"

通过分数条件查询返回指定区间的成员

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
//大于等于0.2小于等于0.5的记录
127.0.0.1:6379> ZRANGEBYSCORE name 0.2 0.5
1) "zc002"
2) "zc003"
3) "zc004"
//大于0.2 小于0.5的记录
127.0.0.1:6379> ZRANGEBYSCORE name (0.2 (0.5
1) "zc003"
2) "zc004"
//显示分数负无穷到正无穷(即所有)的数据
127.0.0.1:6379> ZRANGEBYSCORE name -inf +inf 
1) "zc001"
2) "zc002"
3) "zc003"
4) "zc004"
//从满足情况的元素中 查询下标为2开始的两条记录
127.0.0.1:6379> ZRANGEBYSCORE name -inf +inf LIMIT 2 2
1) "zc003"
2) "zc004"

在Zset中计算指定字典范围内成员数量

127.0.0.1:6379> ZLEXCOUNT name - + //查所有
(integer) 5
//[zc002,zc005]
127.0.0.1:6379> ZLEXCOUNT name [zc002 [zc005
(integer) 4

移除成员

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379>  ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
(integer) 4
127.0.0.1:6379> ZREM name zc001 zc002
(integer) 2
127.0.0.1:6379> ZRANGE name 0 -1
1) "zc003"
2) "zc004"

移除字典区间范围内的值

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
(integer) 4
127.0.0.1:6379> ZREMRANGEBYLEX name - + //移除所有
(integer) 4
127.0.0.1:6379> ZRANGE name 0 -1
(empty list or set)
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
(integer) 4
//移除zc001到zc003之间的数据
127.0.0.1:6379> ZREMRANGEBYLEX name [zc001 [zc003
(integer) 3
127.0.0.1:6379> ZRANGE name 0 -1
1) "zc004"

移除集合中排名区间(下标范围)的所有成员

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
(integer) 4
127.0.0.1:6379> ZREMRANGEBYRANK name 0 2
(integer) 3
127.0.0.1:6379> ZRANGE name 0 -1
1) "zc004"

移除指定分数范围内的值

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
(integer) 4
127.0.0.1:6379> ZREMRANGEBYSCORE name 0.2 0.3
(integer) 2
127.0.0.1:6379> ZRANGE name 0 -1
1) "zc001"
2) "zc004"

返回集合范围内的成员 通过索引下标 分数从高到低

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.2 zc003 0.1 zc004
(integer) 4
127.0.0.1:6379> ZREVRANGE name 0 -1
1) "zc003"
2) "zc002"
3) "zc004"
4) "zc001"

返回指定分数区间范围内的成员 分数从高到低排序

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.2 zc003 0.1 zc004
127.0.0.1:6379> ZREVRANGEBYSCORE name 0.2 0.1
1) "zc003"
2) "zc002"
3) "zc004"
4) "zc001"

返回指定区间范围内成员,按字典倒序

127.0.0.1:6379> ZREVRANGEBYLEX name [zc002 [zc001
1) "zc002"
2) "zc004"
3) "zc001"

返回集合中元素排名 按照分数值从大到小

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
(integer) 4
127.0.0.1:6379> ZREVRANK name zc003
(integer) 1 //从高到低下标1 
127.0.0.1:6379> ZREVRANK name zc002
(integer) 2 //从高到低下标2 

计算一个、多个有序集合的交集 将结果存储在新的key中

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 1 zhangchi001 2 zhangchi002
(integer) 2
127.0.0.1:6379> ZADD nm 2 zhangchi003 4 zhangchi004 5 zhangchi002
(integer) 3
//newns是新集合名 2是运算的集合数
127.0.0.1:6379> ZINTERSTORE newns 2 name nm 
(integer) 1
127.0.0.1:6379>  ZRANGE newns 0 -1 WITHSCORES
1) "zhangchi002"
2) "7" //分数值为两个集合中该项分数自核

计算一个、多个有序集合的并集 将结果存储在新的key中

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 1 zhangchi001 2 zhangchi002
(integer) 2
127.0.0.1:6379> ZADD nm 2 zhangchi003 4 zhangchi004 5 zhangchi002
(integer) 3
127.0.0.1:6379> ZUNIONSTORE newns 2  name nm
(integer) 4 //新集合个数
127.0.0.1:6379> ZRANGE newns 0 -1 WITHSCORES 
1) "zhangchi001"
2) "1"
3) "zhangchi003"
4) "2"
5) "zhangchi004"
6) "4"
7) "zhangchi002"
8) "7"

迭代集合中元素(条件分页查询)

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD name 0.1 zc001 0.2 zc002 0.3 zc003 0.4 zc004 
(integer) 4
127.0.0.1:6379> ZSCAN name 0 MATCH zc*
1) "0" //下一次的光标 如果为0 表示结束
2) 1) "zc001"
   2) "0.10000000000000001"
   3) "zc002"
   4) "0.20000000000000001"
   5) "zc003"
   6) "0.29999999999999999"
   7) "zc004"
   8) "0.40000000000000002"

//!!!这里COUNT不会生效 因为scan
127.0.0.1:6379> ZSCAN name 0 MATCH zc* COUNT 2
1) "0"
2) 1) "zc001"
   2) "0.10000000000000001"
   3) "zc002"
   4) "0.20000000000000001"
   5) "zc003"
   6) "0.29999999999999999"
   7) "zc004"
   8) "0.40000000000000002"

四、三种特殊数据类型

redis除了五种基本数据类型外,还有三种特殊数据类型(基本不常用)
Geospatial(地理位置)、Hyperloglog(基数统计)、BitMaps(位图)
Geospatial(地理位置):一般做附近的人
Hyperloglog(基数统计):特定情况下访问量的统计
BitMaps(位图):实现了直接操作位,一般试用于统计每日活跃用户量

五、事务

redis单条命令是保证原子性的,但是redis事务不保证原子性
  Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
  总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

开启事务:multi
命令入队:
执行命令:exec

1.redis没有事务隔离级别的概念

批量操作的命令在命令入队的时候、执行命令exec之前,命令不会被真实执行,直到exec时候才会被顺序执行

2.redis不保证原子性

redis的单条命令是保证原子性的(没啥实际意义、肯定是对的),但是事务不保证原子性(每条命令执行失败不影响别的命令的继续执行)

3.redis事务的三个阶段

开启事务:MULTI
命令入队:QUEUED
执行命令:EXEC

4.示例

正常执行

127.0.0.1:6379> MULTI //开启事务
OK
127.0.0.1:6379> SET name zhangchi //设置key
QUEUED //入队
127.0.0.1:6379> SET age 18 //设置key
QUEUED
127.0.0.1:6379> GET name //获取value
QUEUED
127.0.0.1:6379> GET age //获取value
QUEUED
127.0.0.1:6379> KEYS * //查询所有key
QUEUED
127.0.0.1:6379> EXEC //执行
1) OK
2) OK
3) "zhangchi"
4) "18"
5) 1) "age"
   2) "name"

取消事务

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET name zhangchi 
QUEUED
127.0.0.1:6379> SET age 18
QUEUED
127.0.0.1:6379> DISCARD //取消事务
OK
127.0.0.1:6379> EXEC //执行事务
(error) ERR EXEC without MULTI //没有事务可被执行
127.0.0.1:6379> DISCARD //取消事务
(error) ERR DISCARD without MULTI //没有事务可被取消
127.0.0.1:6379> GET name
(nil)

语法错误

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET name zhangchi
QUEUED
127.0.0.1:6379> SETAAA BBB CCC //错误的语法会直接报错不能执行事务
(error) ERR unknown command `SETAAA`, with args beginning with: `BBB`, `CCC`, 
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.

代码逻辑错误(运行时异常),其他命令可以正常执行,所以不保证事务原子性

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET name zhangchi
QUEUED
127.0.0.1:6379> SET age 18
QUEUED
127.0.0.1:6379> INCR age
QUEUED
127.0.0.1:6379> INCR name //对字符串增量是运行时异常
QUEUED
127.0.0.1:6379> GET age
QUEUED
127.0.0.1:6379> GET name
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) (integer) 19
//此处抛异常,其他位置语句不报错,正常执行
4) (error) ERR value is not an integer or out of range
5) "19"
6) "zhangchi"

监控

–正常

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SET name zhangchi
OK
127.0.0.1:6379> SET age 18
OK
127.0.0.1:6379> WATCH name age //监控name age
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECR age
QUEUED
127.0.0.1:6379> SET name zc
QUEUED
127.0.0.1:6379> EXEC //name age没有被修改 则事务执行成功(乐观锁)
1) (integer) 17
2) OK
127.0.0.1:6379> MGET name age
1) "zc"
2) "17"

–非正常,监控值中途被修改了

--窗口1
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MSET name zhangchi age 18
OK
127.0.0.1:6379> WATCH name age //监控name age
OK
127.0.0.1:6379> SET name zc001 //修改name
OK

--窗口2
127.0.0.1:6379> SET name zc
OK

--窗口1
127.0.0.1:6379> EXEC
(error) ERR EXEC without MULTI //name被中途修改了 事务抛异常结束
127.0.0.1:6379> MGET name age
1) "zc" //name被窗口2修改
2) "18"

由此可见 redis的监控机制使用的是乐观锁
每次提交执行exec都会被自动释放锁,不论成功与否

六、持久化-RDB

RDB:Redis Databases
在指定时间间隔后,将内存的数据集以快照的方式写入数据库;在恢复数据的时候,直接读取快照文件进行恢复
简单来说就是定时创建快照对数据备份

1.工作原理

在redis进行RDB的时候,redis主线程不会进行io操作的,主线程会开启fork一个子线程来进行操作。同时会默认生成一个dump.rdb的二进制文件中。

2.触发机制

1、满足redis.conf中配置的save参数规则(多长时间有多少个key被修改了等等)
2、FLUSHALL时候
3、退出redis
注意:如果是kill -9杀死进程 不会备份
save的时候会阻塞主线程(同步)
解决该问题使用bgsave(异步,需要多开一个线程,消耗内存)

3.优缺点

优点:
1、适合大规模的数据恢复
2、对数据的完整性要求不高
缺点:
1、有时间间隔,可能会丢失数据
2、fork进程时候创建快照会占用一定的内存空间

七、持久化-AOF

1.工作原理

AOF:Append Only File
以日志的形式记录下所有的写操作,只允许追加文夹,不允许修改。redis会记录下所有的写操作指令,在宕机恢复的时候从前到后执行所有的的操作。
如果需要开启该功能的话

appendonly no //改为yes开启aof

# The name of the append only file (default: "appendonly.aof")

appendfilename "appendonly.aof" //默认文件名

# appendfsync always //每次修改都会同步缓冲区命令 消耗性能
appendfsync everysec //每一秒执行一次同步缓冲区命令 可能丢失一秒的数据
# appendfsync no //由系统决定什么时候同步缓冲区命令 效率最高

2.优缺点

优点:
1、每次修改都会同步文件,文件的完整性更好
2、每次同步都是append的模式,不用消耗磁盘寻址能力的所占用的空间
3、适合灾难性的误删除进行紧急恢复
缺点:
1、相对于文件数aof比rdb更多,修复的速度更慢
2、aof的运行效率也比rdb慢

八、Redis发布订阅(基本不用)

Redis其实也可以做消息中间件使用
Redis提供了发布订阅模式

--订阅端
127.0.0.1:6379> SUBSCRIBE zhangchi //订阅一个zhangchi频道
Reading messages... (press Ctrl-C to quit) //等待接收消息
1) "subscribe" //订阅成功
2) "zhangchi" //频道名称
3) (integer) 1
1) "message" //收到消息
2) "zhangchi" //来自的频道
3) "hahaha" //消息内容
1) "message"
2) "zhangchi"
3) "hehehe"

--发布端
127.0.0.1:6379> PUBLISH zhangchi hahaha //发布hahaha到zhangchi频道
(integer) 1
127.0.0.1:6379> PUBLISH zhangchi hehehe
(integer) 1

--查看活跃的频道
127.0.0.1:6379> PUBSUB channels
1) "zhangchi"
127.0.0.1:6379> PUBSUB channels //如果把订阅者都关闭
(empty list or set)

九、Redis主从复制

十、Redis哨兵模式

以上两个会新开一个文章,到时候链接进来

十一、缓存穿透与雪崩

1.缓存穿透(查不到)

在用户请求数据时候,会现在redis中查找,如果查找不到再去数据库中查找,并缓存进数据库,数量较少可能不会有问题,但是如果遇到秒杀场景所有缓存都查不到时候,压力会全部转移到数据库上,这时候就可能造成数据库崩溃。
解决方案:
1、布隆过滤器
对所有的可能查询的参数以Hash的形式进行存储,以便快速确定是否有结果,在控制层进行校验,不通过的直接返回,减轻系统压力
redis安装使用_第3张图片
2、缓存空对象
一次请求如果在redis和数据库中都没找到,就缓存一个空对象返回
redis安装使用_第4张图片
缺陷:空对象也消耗空间、并且对业务的一致性有影响(会有数据库实际存在,但是查出为空的情况)

2.缓存击穿(量太大,缓存过期)

在缓存过期的那一刻,有大量请求同时访问一个key,瞬间击穿到数据库,造成一瞬间的请求压力过大
微博热点经常有这种情况
解决方案:
1、设置热点数据永不过期
可能会有redis满了 会自动清理的风险
2、加互斥锁(分布式锁)
缓存中没有的话 只放行一个请求去查数据库 并缓存进redis

3.缓存雪崩

跟缓存击穿稍微有点像,雪崩是指同一时间有大量的key同时失效,造成数据库瞬间的压力过大,引起雪崩
redis安装使用_第5张图片

解决方案:
1、redis高可用(集群搭建)
2、限流降级
类似击穿中加互斥锁,限制访问数据库的数量
3、数据遇热
项目部署前,先把所有的数据事先访问一遍,预先加载到redis中
4、将缓存失效时间尽可能设置均匀点

你可能感兴趣的:(数据库,redis)