Redis(二)
2022-09-22 22:46:27

目录
[TOC]

常用操作

Redis默认有16个数据库(redis.conf里配置的)
image.png
默认使用的是第0个,可以使用select来进行切换(类似mysql的use命令)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@hopestation ~]# cd /usr/local/bin  
[root@hopestation bin]# ls //查看当前目录下的文件
redis-benchmark redis-config
redis-check-aof redis-sentinel
redis-check-rdb redis-server redis-cli //等...
[root@hopestation bin]# redis-cli -p 6379
127.0.0.1:6379> select 3 //切换数据库
OK
127.0.0.1:6379[3]> keys *
(empty list or set)
127.0.0.1:6379[3]> select 0 //选择第0个数据库
OK
127.0.0.1:6379> keys * //查看所有key
1) "message"
127.0.0.1:6379> get message //查看message这个key的value
"zhongyuanzhuangwanle"
127.0.0.1:6379> dbsize //查看db大小
(integer) 1
127.0.0.1:6379>

flushdb:清空当前库的数据
flushall:清空所有库的数据
image.png

默认端口是6379

“6379在是手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字。

基础知识

Redis是单线程的

  • 基于内存操作,CPU不是Redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。(较多线程而言,也省去了很多上下文切换线程的时间)
  • Redis是C语言写的,官方提供的数据为10万+的QPS,完全不比同样是使用key-value存储的Memecahe差

Redis为什么单线程还这么快

  1. 误区1:高性能的服务器一定是多线程的?
  2. 误区2:多线程(
    CPU上下文会切换!)一定比单线程效率高
    首先,速度比较:CPU > 内存 > 硬盘
    核心:Redis是将所有的数据全部放在内存中的,是所以单线程去操作的效率就是最高的,多线程(CPU上下文会切换:耗时的操作),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这是最佳的方案

上面说了一堆单线程的好处,Redis6.0还是引入了多线程。。真香

引入原因概括:因为读写网络的read/write系统调用在Redis执行期间占用了大部分CPU时间,如果把网络读写做成多线程的方式对性能会有很大提升。
具体参考此博主文章

五大数据类型

image.png

全段翻译:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库缓存消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
127.0.0.1:6379> keys * //查看所有dkey
(empty list or set)
127.0.0.1:6379> set message ceshi //set key
OK
127.0.0.1:6379> set age 14
OK
127.0.0.1:6379> keys *
1) "age"
2) "message"
127.0.0.1:6379> exists name // 查看key是否存在
(integer) 0
127.0.0.1:6379> exists message
(integer) 1
127.0.0.1:6379> move age 1 //移动age到1库
(integer) 1
127.0.0.1:6379> keys *
1) "message"
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys * //查看1库里的age
1) "age"
127.0.0.1:6379[1]> get age
"14"
127.0.0.1:6379[1]> expire age 10 //设过期时间
(integer) 1
127.0.0.1:6379[1]> ttl age
//time to live 查看剩余的存活时间
(integer) 6
127.0.0.1:6379[1]> set age 14
OK
127.0.0.1:6379[1]> set message ceshi
OK
127.0.0.1:6379[1]> type age //查看key的类型
string
127.0.0.1:6379[1]> type message

String

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379[1]> set message ceshi //存入 message这个key
OK
127.0.0.1:6379[1]> type message
string
127.0.0.1:6379[1]> append message _append //追加字符串,若当前key不存在,则会新建一个字符串
(integer) 12
127.0.0.1:6379[1]> get message //再次查看
"ceshi_append"
127.0.0.1:6379[1]> strlen message //获得长度
(integer) 12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
##########################################################
127.0.0.1:6379[1]> set views 0
OK
127.0.0.1:6379[1]> get views
"0"
#可以用来计数,比如网站初始浏览量为0
127.0.0.1:6379[1]> incr views # 自增1 浏览量+1
(integer) 1
127.0.0.1:6379[1]> incr views
(integer) 2
127.0.0.1:6379[1]> get views
"3"
127.0.0.1:6379[1]> decr views # 自减1 浏览量-1
(integer) 2
127.0.0.1:6379[1]> decr views
(integer) 1
127.0.0.1:6379[1]> incrby views 10 #可以设定步长,比如 自增 10
(integer) 10
127.0.0.1:6379[1]> decrby views 6 # 自减6 浏览量-6
(integer)
################################
# 获取字符串的某个范围
127.0.0.1:6379[1]> get message
"ceshi_append"
127.0.0.1:6379[1]> getrange message 0 3 #截取字符串[0,3]
"cesh"
127.0.0.1:6379[1]> getrange message 0 -1 #夺取全部的字符串 和 get key是一样的
"ceshi_append"
127.0.0.1:6379[1]> getrange name 0 3 # 若没有key 返回空
""
# 替换
127.0.0.1:6379[1]> set name 1111
OK
127.0.0.1:6379[1]> get name
"1111"
127.0.0.1:6379[1]> setrange name 2 xxx # 从第二个字符开始替换
(integer) 5
127.0.0.1:6379[1]> get name
"11xxx"
################################
# setex (set with expire) 设置过期时间
# setnx (set if not exist) 不存在再设置 (在分布式锁中会常常使用!)
127.0.0.1:6379[1]> setex message 30 "hello"
#设置message的值为 hello,并且30秒后过期
OK
127.0.0.1:6379[1]> ttl message
(integer) 26
127.0.0.1:6379[1]> ttl message
(integer) 24
127.0.0.1:6379[1]> get message
"hello"
127.0.0.1:6379[1]> setnx mykey "redis"
#如果mykey不存在,则创建mykey,返回1
(integer) 1
127.0.0.1:6379[1]> keys *
1) "mykey"
127.0.0.1:6379[1]> setnx mykey "mongoDb"
#如果mykey存在,则创建失败,返回0
(integer) 0
127.0.0.1:6379[1]> keys *
1) "mykey"
127.0.0.1:6379[1]> get mykey
"redis"
################################
# mset 同时设置多个值 若key重复,后面的设置会覆盖前面的
# msetnx 若key都不存在 则设置多个key(原子性的,要么一起成功,要么一起失败)
127.0.0.1:6379> mset k2 v1 k2 v3 k3 v3 # 设置了k2,k3 (k2后面覆盖前面了的)
OK
127.0.0.1:6379> keys *
1) "k2"
2) "message"
3) "k3"
127.0.0.1:6379> get k2
"v3"
127.0.0.1:6379> get k3
"v3"
127.0.0.1:6379> msetnx k1 v1 k2 v2 # 这里k2已经存在,但k1不存在。还是会一起失败
(integer) 0
127.0.0.1:6379> keys *
1) "k2"
2) "message"
3) "k3"
# key可以设计成 {对象名}:{id}:{属性名} 的形式
# mget 获取多个key
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 15
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "15"
127.0.0.1:6379> get user:1:name
"zhangsan"
################################
# getset 返回旧值(没有返回nil),然后设置新值
127.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongoDB
"redis"
127.0.0.1:6379> get db
"mongoDB"
##########################################################

String类型的使用场景:
value除了代表字符串,还可以代表数字!

  • 计数器
  • 统计多单位的数量
  • 粉丝数
  • 对象缓存存储

List

基本的数据类型,列表
image.png
在Redis里,可以把list完成 栈、队列、阻塞队列

所有的list命令都是用‘l’开头的,Redis不区分大小写命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
##########################################################
# list 值可以重复
# lpush 从左侧添加一个值 (lpush 即 left push)
# rpush 从右侧添加一个值 (rpush 即 right push)
127.0.0.1:6379> lpush list one # 将一个或者多个值,放在列表的头部
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 获取全部
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1 # 获取指定的范围
1) "three"
2) "two"
127.0.0.1:6379> rpush list right # 从右侧(尾部)插入一个值
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
################################
# lpop 从左侧移除一个值 (即 left pop )
# rpop 从右侧移除一个值 (即 right pop )
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lpop list
"three"
127.0.0.1:6379> rpop list
"right"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
# lindex 通过下标获取值
127.0.0.1:6379> lindex list 0
"two"
# llen 获取长度 (list length)
127.0.0.1:6379> llen list
(integer) 2
###############################
# lrem 根据key和个数 移除指定的值 (因为list的值可以重复,所以需要指定个数)
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 one
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
127.0.0.1:6379> lrem list 2 three # 这里也可以写成1,只移除一个three
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "two"
###############################
# ltrim 截取(留下)指定下标范围的值,范围外的数据被移除了
127.0.0.1:6379> lrange mylist 0 -1
1) "hello4"
2) "hello3"
3) "hello2"
4) "hello1"
127.0.0.1:6379> ltrim mylist 1 2
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello3"
2) "hello2"
##########################################################


未完待续…

参考资料

  • 狂神说
Prev
2022-09-22 22:46:27
Next