Redis入门10-事务

Redis 事务的本质就是一次性、顺序性、排他性的执行一个队列中的一系列命令

Redis命令如下:

  • MULTI :开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令系列。
  • EXEC:执行事务中的所有操作命令。
  • DISCARD:取消事务,放弃执行事务块中的所有命令。
  • WATCH:监视一个或多个key,如果事务在执行前,key(或多个key)被其他命令修改,则事务被中断,不执行事务中的任何命令。
  • UNWATCH:取消WATCH对所有key的监视

基本使用

情况一:标准事务的执行

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(TX)> set k1 11
QUEUED
127.0.0.1:6379(TX)> set k2 22
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
127.0.0.1:6379> get k1
"11"
127.0.0.1:6379> get k2
"22"
127.0.0.1:6379>

情况二:事务取消

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k3 33
QUEUED
127.0.0.1:6379(TX)> set k4 44
QUEUED
127.0.0.1:6379(TX)> discard
OK
127.0.0.1:6379> get k3
(nil)
127.0.0.1:6379> get k4
(nil)

情况三:事务异常(语法异常)

开启事务后,修改k1值为111,修改k2的值为222,但是语法错误,导致提交的时候都保留原值

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 111
QUEUED
127.0.0.1:6379(TX)> sets k2 222
(error) ERR unknown command 'sets', with args beginning with: 'k2' '222'
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
"11"
127.0.0.1:6379> get k2
"22"

情况四:事务异常(运行时异常)

开启事务后,修改k1值为1111,修改k2的值为2222,但是类型错误,都能提交,执行时只有一个成功一个失败

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> multi 
OK
127.0.0.1:6379(TX)> set k1 1111
QUEUED
127.0.0.1:6379(TX)> lpush k2 2222
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get k1
"1111"
127.0.0.1:6379> get k2
"22"

也就是说,当事务提交后,并不能保证所有的请求都能成功,可能出现一部分成功,一部分失败

WATCH

WATCH 命令可以为 Redis 事务提供 check-and-set(CAS)行为

WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败

假设需要原子性地为某个值进行增 1 操作(假设 INCR 不存在),开两个窗口:

  1. 另一个在执行过程中(exec 提交事务前执行修改操作)修改key

    1
    set k5 3
  2. 一个执行 Watch 并执行事务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> watch k5
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> set k5 2
    QUEUED
    127.0.0.1:6379(TX)> set k6 1
    QUEUED
    127.0.0.1:6379(TX)> exec
    (nil)
    127.0.0.1:6379> get k5
    "3"
    127.0.0.1:6379> get k6
    (nil)

可以看出得出的结果是 3,另外需要注意的是 k6 的值也设置失败,也就是事务所有请求都失败了(而且测试发现全部失败与命令在事务的第几条没有关系 )

参考链接

  1. https://pdai.tech/md/db/nosql-redis/db-redis-x-trans.html