Redis 操作事务
PPG007 ... 2021-12-28 About 2 min
# Redis 操作事务
Tips
redis 单条命令保证原子性。
但是事务不保证原子性。
一次性、顺序性、排他性。
# Redis 事务阶段
- 开启事务(MULTI)。
- 命令入队。
- 执行事务(EXEC)。
# 基础命令
创建事务:
150.158.153.216:6379> multi
OK
150.158.153.216:6379> set key1 key1
QUEUED
150.158.153.216:6379> set key2 key2
QUEUED
150.158.153.216:6379> get key1
QUEUED
150.158.153.216:6379> set key3 key3
QUEUED
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
执行事务:
150.158.153.216:6379> exec
1) OK
2) OK
3) "key1"
4) OK
1
2
3
4
5
2
3
4
5
取消事务:
150.158.153.216:6379> multi
OK
150.158.153.216:6379> set a a
QUEUED
150.158.153.216:6379> discard
OK
150.158.153.216:6379> get a
(nil)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 事务中的异常
语法错误:
# 所有命令都不会执行
150.158.153.216:6379> multi
OK
150.158.153.216:6379> set a a
QUEUED
150.158.153.216:6379> set b b
QUEUED
150.158.153.216:6379> asfafargq
(error) ERR unknown command `asfafargq`, with args beginning with:
150.158.153.216:6379> getset c
(error) ERR wrong number of arguments for 'getset' command
150.158.153.216:6379> set d d
QUEUED
150.158.153.216:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
150.158.153.216:6379> keys *
(empty list or set)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
操作错误(运行时异常):
# 正常命令依然正常执行
150.158.153.216:6379> multi
OK
150.158.153.216:6379> incr a
QUEUED
150.158.153.216:6379> set b b
QUEUED
150.158.153.216:6379> get b
QUEUED
150.158.153.216:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) "b"
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 乐观锁
通过 watch 和 unwatch 命令开启/关闭对 key 的监视。
正常执行:
150.158.153.216:6379> set money 100
OK
150.158.153.216:6379> set out 0
OK
150.158.153.216:6379> watch money
OK
150.158.153.216:6379> multi
OK
150.158.153.216:6379> decrby money 20
QUEUED
150.158.153.216:6379> incrby out 20
QUEUED
150.158.153.216:6379> exec
1) (integer) 80
2) (integer) 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
异常执行:
客户端 1:
150.158.153.216:6379> watch money out
OK
150.158.153.216:6379> multi
OK
150.158.153.216:6379> decrby money 5
QUEUED
150.158.153.216:6379> incrby out 5
QUEUED
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
客户端 1 的事务先不执行,此时插入客户端 2 的操作。
客户端 2:
150.158.153.216:6379> decrby out 10
(integer) 10
1
2
2
然后客户端 1 再执行:
150.158.153.216:6379> exec
(nil)
150.158.153.216:6379> get money
"80"
1
2
3
4
2
3
4
事务没有执行。
Tips
如果希望再次执行事务,先用 unwatch 解锁再使用 watch 重新加锁。