0%

Redis笔记

Redis

五大基础数据类型

String

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
127.0.0.1:6379> ping      //测试是否连接成功
PONG

127.0.0.1:6379> set name wang //设置值 set 键 值
OK

127.0.0.1:6379> get name //获取值 get 键
"wang"

127.0.0.1:6379> select 3 //切换数据库(redis中一个16个数据库) select 编号
OK

127.0.0.1:6379[3]> select 0
OK

127.0.0.1:6379> dbsize //查看当前数据库大小
(integer) 2

127.0.0.1:6379> keys * //查看所有的键
1) "name"
2) "\xac\xed\x00\x05t\x00\x05mykey"


127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> set key2 value2
OK
127.0.0.1:6379> keys key* //模糊匹配
1) "key1"
2) "key2"


127.0.0.1:6379> flushdb //清空当前数据库
OK

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

127.0.0.1:6379> FLUSHALL //清空全部数据库
OK

127.0.0.1:6379> exists name //是否存在某个键 exists 键
(integer) 1

127.0.0.1:6379> expire name 5 //设置某个键过期时间 expire 键 设置时间
(integer) 1

127.0.0.1:6379> ttl name //查看剩余时间 ttl 键
(integer) -2

127.0.0.1:6379> move name 1 //将当前数据库的 key 移动到给定的数据库当中。 move 键 库
(integer) 1

127.0.0.1:6379> append name hello //追加 append 键 值 (如果没有这个键,就会新建一个)
(integer) 9

127.0.0.1:6379> incr views
(integer) 7

127.0.0.1:6379> incr views //加一(自增) incr 键
(integer) 8

127.0.0.1:6379> decr views //减一(自减) decr 键
(integer) 7

127.0.0.1:6379> incrby views 10 //加10(相当于 i+=i ) incrby 键 要加的次数
(integer) 17

127.0.0.1:6379> decrby views 15 //减15(相当于 i-=i ) decrby 键 要减的次数
(integer) 2


127.0.0.1:6379> set name wangtianyi
OK
127.0.0.1:6379> get name
"wangtianyi"
127.0.0.1:6379> getrange name 0 5 //截取字符串 [0,5] getrange 键 起始索引 结束索引
"wangti"
127.0.0.1:6379> getrange name 0 -1 //截取全部字符串 getrange 键 0 -1
"wangtianyi"


127.0.0.1:6379> set key1 aaaaa
OK
127.0.0.1:6379> get key1
"aaaaa"
127.0.0.1:6379> setrange key1 1 bb //替换字符串 setrange 键 起始位置 替换的字符
(integer) 5
127.0.0.1:6379> get key1
"abbaa"



127.0.0.1:6379> setex mykey 30 "hello" //设置过期时间 设置mykey的值为“hello”,30秒后过期
OK
127.0.0.1:6379> ttl mykey //查看还剩多久过期
(integer) 23
127.0.0.1:6379> setnx id 11111 //不存在就创建(分布式锁中会用到)
(integer) 1
127.0.0.1:6379> keys *
1) "key1"
2) "id"
3) "name"
127.0.0.1:6379> ttl mykey
(integer) -2
127.0.0.1:6379> setnx id 22222 //如果存在,就创建失败
(integer) 0
127.0.0.1:6379> get id
"11111"



127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 //批量设置 mset 键1 值1 键2 值2 ......
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
127.0.0.1:6379> mget k1 k2 k3 //批量获取 mget 键1 键2 ....
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 //批量设置,如果都不存在就创建(原子性,要么都成功,要么都失败)
(integer) 0
127.0.0.1:6379> get k4
(nil)



key(user:id:filed) value
127.0.0.1:6379> mset user:1:name wang user:1:id 10 //设置user:1对象 name属性,值为wang
OK
127.0.0.1:6379> mget user:1:name user:1:id //获取user对象对应属性的值
1) "wang"
2) "10"





127.0.0.1:6379> getset db redis // 先get再set(先get,如果没有则返回null,然后再set) getset 键 值
(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"





List 有序可重复

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
127.0.0.1:6379> lpush list one   //向list列表中插入值(插入到列表的头部 左进)
(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> lpush list foer
(integer) 4
127.0.0.1:6379> lrange list 0 2
1) "foer"
2) "three"
3) "two"
127.0.0.1:6379> rpush list five //从右边插入值(尾部)
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "foer"
2) "three"
3) "two"
4) "one"
5) "five"
127.0.0.1:6379> lpop list //移除list中第一个元素
"foer"
127.0.0.1:6379> rpop list //移除list中最后一个元素
"five"
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lindex list 0 //通过下标获得list中某一个的值
"three"
127.0.0.1:6379> llen list //获取list的长度
(integer) 3



127.0.0.1:6379> lpush list 1
(integer) 1
127.0.0.1:6379> lpush list 2
(integer) 2
127.0.0.1:6379> lpush list 3
(integer) 3
127.0.0.1:6379> lpush list 3
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "3"
3) "2"
4) "1"
127.0.0.1:6379> lrem list 1 1 // 移除list集合中指定元素 lrem list 个数 要移除的元素 (移除了list中1个1)
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "3"
3) "2"
127.0.0.1:6379> lrem list 2 3 // 移除list集合中指定元素 lrem list 个数 要移除的元素 (移除了list中2个3)
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "2"


127.0.0.1:6379> lrange mylist 0 -1
1) "wang1"
2) "wang2"
3) "wang3"
4) "wang4"
127.0.0.1:6379> ltrim mylist 1 2 //通过下标截取指定长度 ltrim 键 起始下标 长度
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "wang2"
2) "wang3"



127.0.0.1:6379> lpush user1 wang1
(integer) 1
127.0.0.1:6379> lpush user1 wang2
(integer) 2
127.0.0.1:6379> lpush user1 wang3
(integer) 3
127.0.0.1:6379> rpoplpush user1 user2 //将user1中最后一个元素移除,并添加到user2中
"wang1"
127.0.0.1:6379> lrange user2 0 -1
1) "wang1"




127.0.0.1:6379> exists list //判断当前数据库是否有list
(integer) 0
127.0.0.1:6379> lset list 0 wang // 如果没有键的话,替换时不会自动创建
(error) ERR no such key
127.0.0.1:6379> lpush list wang1
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "wang1"
127.0.0.1:6379> lset list 0 wang2 //将list集合中,0下标的值替换成wang2
OK
127.0.0.1:6379> lrange list 0 0
1) "wang2"







127.0.0.1:6379> rpush list 1
(integer) 1
127.0.0.1:6379> rpush list 2
(integer) 2
127.0.0.1:6379> rpush list 3
(integer) 3
127.0.0.1:6379> rpush list 4
(integer) 4
127.0.0.1:6379> linsert list after 4 5 //在list集合中,在4后面插入一个5
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> linsert list before 1 0 //在list集合中,在1前面插入0
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"

image-20210805122629875

Set 无序不可重复

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
127.0.0.1:6379> sadd myset hello world   //向set中添加元素   sadd  键  值1  值2
(integer) 2
127.0.0.1:6379> smembers myset //查看set中的所有元素 smembers 键
1) "hello"
2) "world"
127.0.0.1:6379> sadd myset wang //向set中添加元素 sadd 键 值
(integer) 1
127.0.0.1:6379> smembers myset
1) "hello"
2) "world"
3) "wang"
127.0.0.1:6379> sismember myset wang //查看set中是否存在某个值 sismember 键 值
(integer) 1
127.0.0.1:6379> sismember myset wang1
(integer) 0
127.0.0.1:6379> scard myset //获取set某个键的元素个数 scard 键
(integer) 3

127.0.0.1:6379> srem myset wang1 //移除set中指定元素 srem 键 值
(integer) 1


127.0.0.1:6379> smembers myset
1) "hello"
2) "world"
3) "wang"
127.0.0.1:6379> srandmember myset // 随机抽取一个元素 srandmember 键
"world"
127.0.0.1:6379> srandmember myset
"wang"
127.0.0.1:6379> srandmember myset 2 // 随机抽取多个元素 srandmember 键 个数
1) "world"
2) "wang"



127.0.0.1:6379> smembers myset
1) "hello"
2) "world"
3) "wang"
127.0.0.1:6379> spop myset //随机移除一个元素 spop 键
"world"

127.0.0.1:6379> smembers myset
1) "2"
2) "1"
3) "4"
4) "hello"
5) "3"
6) "5"
127.0.0.1:6379> spop myset 2 //随机移除多个个元素 spop 键 个数
1) "1"
2) "5"



//将一个指定的值移动到另一个set集合
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> smembers set2
1) "4"
2) "5"
3) "6"
127.0.0.1:6379> smove set1 set2 3 // smove 键1 键2 键1中的值 (将键一中的值移动到键2)
(integer) 1
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
127.0.0.1:6379> smembers set2
1) "3"
2) "4"
3) "5"
4) "6"




127.0.0.1:6379> sadd set1 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sadd set2 5 6 7 8 9
(integer) 5
127.0.0.1:6379> sdiff set1 set2 //差集
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> sinter set1 set2 //交集(可以用来做共同好友)
1) "5"
127.0.0.1:6379> sunion set1 set2 //并集
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"
9) "9"

Hash(Map集合 k-v)

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
127.0.0.1:6379> hset hash1 k1 v1  //向hash中添加一个元素   hset  键  值(key value)  
(integer) 1
127.0.0.1:6379> hget hash1 k1 //获取hash中一个key的值
"v1"
127.0.0.1:6379> hmset hash1 k1 v1 k2 v2 //向hash中添加多个元素 hset 键 值1(key value) 值2(key value)
OK
127.0.0.1:6379> hmget hash1 k1 k2 //获取hash中多个key的值
1) "v1"
2) "v2"
127.0.0.1:6379> hgetall hash1 //获取hash中全部元素
1) "k1" //键1
2) "v1" //值1
3) "k2" //键2
4) "v2" //值2


127.0.0.1:6379> hdel hash1 k1 //删除hash中指定键对应的值 hdel 键 key名
(integer) 1
127.0.0.1:6379> hgetall hash1
1) "k2"
2) "v2"




127.0.0.1:6379> hgetall hash1
1) "k2"
2) "v2"
3) "k1"
4) "v1"
5) "k3"
6) "v3"
127.0.0.1:6379> hlen hash1 //获取hash表中 k-v键值对 数量
(integer) 3
127.0.0.1:6379> hexists hash1 k1 //判断hash表中,指定键值对是否存在 hexists 键 key
(integer) 1
127.0.0.1:6379> hexists hash1 k5
(integer) 0



127.0.0.1:6379> hkeys hash1 // 只获得hash中所有的key
1) "k2"
2) "k1"
3) "k3"
127.0.0.1:6379> hvals hash1 // 只获得hash中所有的value
1) "v2"
2) "v1"
3) "v3"



127.0.0.1:6379> hgetall hash1
1) "k2"
2) "v2"
3) "k1"
4) "v1"
5) "k3"
6) "v3"
7) "age"
8) "2"
127.0.0.1:6379> hincrby hash1 age i // 自增i hincrby 键 key i (i+=i)
(integer) 3
127.0.0.1:6379> hincrby hash1 age -i // 自减i hincrby 键 key -i (i-=i)
(integer) 2



127.0.0.1:6379> hsetnx hash1 k5 v5 //如果不存在就创建
(integer) 1
127.0.0.1:6379> hsetnx hash1 k5 v //如果存在就不创建
(integer) 0

Zset(有序集合)

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
127.0.0.1:6379> zadd salary 5000 wang1  1000 wang2  1500 wang3   //向Zset中添加三个元素  zadd  键   分数1  值1
(integer) 3
127.0.0.1:6379> zrangebyscore salary -inf +inf //从小到大排序
1) "wang2"
2) "wang3"
3) "wang1"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores //从小到大排序,并显示分数
1) "wang2"
2) "1000"
3) "wang3"
4) "1500"
5) "wang1"
6) "5000"
127.0.0.1:6379> zrevrange salary 0 -1 withscores //从大到小排序,并显示分数
1) "wang1"
2) "5000"
3) "wang2"
4) "2000"
5) "wang3"
6) "1500"
127.0.0.1:6379> zrangebyscore salary 1500 2000 //获取[1500,2000]间的值
1) "wang3"
127.0.0.1:6379> zrangebyscore salary 1500 5000 withscores //获取[1500,5000]间的值,并显示分数
1) "wang3"
2) "1500"
3) "wang1"
4) "5000"


127.0.0.1:6379> zrangebyscore salary -inf +inf withscores
1) "wang2"
2) "1000"
3) "wang3"
4) "1500"
5) "wang1"
6) "5000"
127.0.0.1:6379> zrem salary wang2 //移除Zset中指定元素
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores
1) "wang3"
2) "1500"
3) "wang1"
4) "5000"


127.0.0.1:6379> zcard salary //获取集合中元素个数
(integer) 2



127.0.0.1:6379> zrevrange salary 0 -1 withscores //从大到小排序,并显示分数
1) "wang1"
2) "5000"
3) "wang2"
4) "2000"
5) "wang3"
6) "1500"
127.0.0.1:6379> zcount salary -inf +inf //获取指定区间的成员数量 zcount 键 最小 最大
(integer) 3
127.0.0.1:6379> zcount salary 1500 2000
(integer) 2

三种特殊数据类型

Geospatial地理位置

有效的经度从-180度到180度。
有效的纬度从-85.05112878度到85.05112878度。

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing   //添加地理位置  geoadd  键  经度、纬度、名称
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 114.05 22.52 shenzheng 120.16 30.24 hangzhou
(integer) 2



127.0.0.1:6379> geopos china:city beijing //获取指定城市的经度和纬度
1) 1) "116.39999896287918"
2) "39.900000091670925"
127.0.0.1:6379> geopos china:city shanghai
1) 1) "121.47000163793564"
2) "31.229999039757836"
127.0.0.1:6379> geopos china:city chongqing shenzheng //geopos 键 城市1 城市2
1) 1) "106.49999767541885"
2) "29.529999579006592"
2) 1) "114.04999762773514"
2) "22.520000087950386"




127.0.0.1:6379> geodist china:city beijing shanghai //计算两个城市之间的距离 geodist 键 城市1 城市2
"1067378.7564"
127.0.0.1:6379> geodist china:city beijing shanghai km //计算两个城市之间的距离 geodist 键 城市1 城市2 单位
"1067.3788"



127.0.0.1:6379> georadius china:city 110 30 1000 km //以 110 30 这个经纬度为中心,寻找方圆1000km内的城市
1) "chongqing"
2) "shenzheng"
3) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 500 km
1) "chongqing"



//以 110 30 这个经纬度为中心,寻找方圆1000km内的城市,并显示到中心的距离
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist
1) 1) "chongqing"
2) "341.9374"
2) 1) "shenzheng"
2) "924.6408"
3) 1) "hangzhou"
2) "977.5143"

//以 110 30 这个经纬度为中心,寻找方圆1000km内的城市,并显示各城市经纬度
127.0.0.1:6379> georadius china:city 110 30 1000 km withcoord
1) 1) "chongqing"
2) 1) "106.49999767541885"
2) "29.529999579006592"
2) 1) "shenzheng"
2) 1) "114.04999762773514"
2) "22.520000087950386"
3) 1) "hangzhou"
2) 1) "120.16000002622604"
2) "30.240000322949022"


//以 110 30 这个经纬度为中心,寻找方圆1000km内的城市,并显示到中心的距离 ,各城市经纬度 限制查询出来的个数(count)
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist withcoord count 1
1) 1) "chongqing"
2) "341.9374"
3) 1) "106.49999767541885"
2) "29.529999579006592"
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist withcoord count 3
1) 1) "chongqing"
2) "341.9374"
3) 1) "106.49999767541885"
2) "29.529999579006592"
2) 1) "shenzheng"
2) "924.6408"
3) 1) "114.04999762773514"
2) "22.520000087950386"
3) 1) "hangzhou"
2) "977.5143"
3) 1) "120.16000002622604"
2) "30.240000322949022"


127.0.0.1:6379> georadiusbymember china:city beijing 1000 km //以城市为中心,多少范围内的所有城市
1) "beijing"
127.0.0.1:6379> georadiusbymember china:city beijing 2000 km
1) "chongqing"
2) "shenzheng"
3) "hangzhou"
4) "shanghai"
5) "beijing"



//将二维的经纬度转换为一维的字符串,如果两个字符串越接近,表明距离越近
127.0.0.1:6379> geohash china:city beijing shanghai
1) "wx4fbxxfke0"
2) "wtw3sj5zbj0"




127.0.0.1:6379> zrange china:city 0 -1 //查看所有城市
1) "chongqing"
2) "shenzheng"
3) "hangzhou"
4) "shanghai"
5) "beijing"
127.0.0.1:6379> zrem china:city beijing //删除指定城市
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "shenzheng"
3) "hangzhou"
4) "shanghai"

Hyperloglog 基数统计

网页的UV( UV:独立访客 一个人访问一个网站多次,但是还是算作一个人)

传统的方式,set保存用户的id,然后统计set中元素的数量

大数据量时可能会有误差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
127.0.0.1:6379> pfadd pf1 a b c d e f g     //向Hyperloglog中添加元素  pfadd  键  值1.....  
(integer) 1
127.0.0.1:6379> pfcount pf1 //统计元素个数(去重) pfcount 键
(integer) 7
127.0.0.1:6379> pfadd pf2 a a c c b b d d
(integer) 1
127.0.0.1:6379> pfcount pf2
(integer) 4
127.0.0.1:6379> pfmerge pf3 pf1 pf2 //合并 pfmerge 新键 要合并的键
OK
127.0.0.1:6379> pfcount pf3
(integer) 7




Bitmap位图场景

统计用户信息,活跃,不活跃;登录,未登录;打卡,未打卡;两个状态的都可以用Bitmap

Bitmap位图,数据结构!操作二进制位来进行记录,就只有0,1两种状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
127.0.0.1:6379> setbit sign 0 1   //设置    setbit 键  名  状态
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 0
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
127.0.0.1:6379> getbit sign 1 //获取状态 getbit 键 名
(integer) 1
127.0.0.1:6379> getbit sign 2
(integer) 0
127.0.0.1:6379> bitcount sign //统计为1的所有状态 bitcount 键
(integer) 4

事务

Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!

一次性(在一个队列中一次性执行)、顺序性(在队列中按照顺序执行)、排他性(事务在执行时不会被干扰)!执行一系列的命令

Redis事务没有隔离级别的概念

所有命令在事务中,并没有被执行!只有发起执行命令的时候才会执行! Exec(执行)

Redis单条命令保存原子性,但是事务不保证原子性

redis事务:

  • 开启事务(multi)
  • 命令入队()
  • 执行事务(exec)
1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> multi  //开启事务
OK
127.0.0.1:6379> set k1 v1 //命令入队
QUEUED
127.0.0.1:6379> set k2 v2 //命令入队
QUEUED
127.0.0.1:6379> get k2 //命令入队
QUEUED
127.0.0.1:6379> exec //执行事务
1) OK
2) OK
3) "v2"

事务执行完后就没了,如果还要用事务,就需要重新开启。

取消事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> multi  //开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> discard //取消事务
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI //报错(没有要执行的事务)
127.0.0.1:6379> get k3
(nil)

编译时异常(代码有问题!命令有错),在事务中所有的命令都不会被执行!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3 //错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> exec //执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1 //所有的命令都不会被执行
(nil)

运行时异常(比如1/0),如果事务队列中存在语法 错误,那么执行命令的时候,其他命令可以正常的执行,错误命令抛出异常!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> incr k1 //字符型不能自增(编译时不报错,执行时报错,不影响后面代码的执行)
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range //报错,但不影响后面代码的执行
3) OK
4) OK
5) "v1"
6) "v2"

监控 (Watch) 可以实现乐观锁

悲观锁:

  • ​ 很悲观,认为什么时候都会出问题,无论做什么都会加锁(效率低)

乐观锁:

  • 很乐观,认为什么时候都不会出问题,所以不会上锁!

  • 获取version(数据版本号 :表示数据被修改的次数)

  • 更新的时候比较version(在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功)

单线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money //监视 money 对象
OK
127.0.0.1:6379> multi //事务正常结束,数据期间没有发生变动,这个时候就正常执行成功!
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20

测试多线程修改值,使用watch可以当作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
//线程1
127.0.0.1:6379> watch money //监视 money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED
127.0.0.1:6379> exec //事务执行之前,线程2修改了money的值,这个时候,就会导致事务执行失败!
(nil)



//线程2
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 1000
OK



//如果事务执行失败
127.0.0.1:6379> unwatch //如果发现事务执行失败,就先解锁
OK
127.0.0.1:6379> watch money //获取最新的值,再次监控,select version
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED
127.0.0.1:6379> exec //比对监视的是否发生了变化,如果没有变化,那么可以执行成功,如果变了就执行失败!
1) (integer) 990
2) (integer) 30

Jedis

Jedis是Redis官方推荐的Java连接开发工具!