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

执行事务:

150.158.153.216:6379> exec
1) OK
2) OK
3) "key1"
4) OK
1
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

# 事务中的异常

语法错误:

# 所有命令都不会执行
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

操作错误(运行时异常):

# 正常命令依然正常执行
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

# 乐观锁

通过 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

异常执行:

客户端 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

客户端 1 的事务先不执行,此时插入客户端 2 的操作。

客户端 2:

150.158.153.216:6379> decrby out 10
(integer) 10
1
2

然后客户端 1 再执行:

150.158.153.216:6379> exec
(nil)
150.158.153.216:6379> get money
"80"
1
2
3
4

事务没有执行。

Tips

如果希望再次执行事务,先用 unwatch 解锁再使用 watch 重新加锁。

Last update: December 28, 2021 13:51
Contributors: PPG007