2024-05-02
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/2116514153

回答

首先,Redis 是支持事务的。Redis 的事务机制提供了一种一次性、按顺序执行一组命令的机制。

它的实现原理是将一组命令压入到事务队列中,然后按照 FIFO 的顺序依次执行,同时在执行这一组命令期间不允许其他命令插入,保证了这组命令在一个原子操作中完成。

Redis 提供以下 5 个命令来实现事务:

  • MULTI:用来标记一个事务块的开始。
  • EXEC:执行事务块中的所有命令。
  • DISCARD:取消事务,放弃执行事务块内的所有命令。这个命令会清除事务队列并退出事务。
  • WATCH:用于乐观锁,它可以监视一个或多个键,如果在执行事务前这些键被其他命令改变了,那么事务将被取消(EXEC会返回null表示事务未执行)
  • UNWATCH:取消 WATCH 命令对所有 key 的监视。

Redis 事务详解

在 Redis 中,一个事务从开始到结束会经历以下3个阶段:

  1. 事务开始
  2. 命令入队
  3. 事务执行

MULTI 命令开启事务,EXEC 命令执行事务,其形式如下:

multi

command1()
command2()

...

commandn()

exec/discard

multi 标志着事务的开始,在 multi 之后的命令都不会执行,全部进入事务队列中,直到服务器接收 exec 或者 discard 才会开始执行或者放弃整个事务,当执行完整个事务后,Redis 会一次性返回所有命令的运行结果。如下:

事务开启:MULTI

MULTI 标志着事务的开始,可以将执行该命令的客户端从非事务态切换的事务态。

MULTI 命令后,Redis 接受该客户端的后续命令后并不会立刻执行,而是将其放置在事务队列中。

该命令的运行如下:

127.0.0.1:6379> MULTI
OK

总是会返回 OK 字符串。

命令入队

当客户端处于非事务态时,这个客户端发送的命令会被立刻执行:

当客户端使用 MULTI 命令进入事务态,这个时候客户端发送的命令不会立刻执行,而是将其放入到事务队列中,向客户端回复 QUEUED,如下:

事务执行:EXEC

当我们在一个处于事务态的客户端执行EXEC,服务器会按照 FIFO 的顺序执行该客户端对应的事务队列中所有命令,然后将执行结果一次性返回给客户端:

使用 EXEC 执行后,客户端会恢复到非事务状态。

事务取消:DISCARD

DISCARD清除所有先前在一个事务中放入的队列的命令,然后恢复到非事务状态。

监视器:WATCH

WATCH 用于在执行事务时监视一个或多个 key。如果在事务执行之前,这些键的值被其他命令改变了,那么这个事务将会被拒绝执行,并向客户端返回 nil。

即,在一个事务开始之前,我们可以通过 WATCH 命令监视一个或多个 key。一旦某个 key 被WATCH,如果该 key 在我们执行 EXEC 命令之前被修改(包括设置新值、删除等),Redis 将取消这个事务的执行。例如:

我们用 WATCH 监视 key balance,然后开启事务,执行 DECRBY balance 50,注意这个时候不要立刻执行 EXEC,我们需要另开一个客户端,将 balance 改变:

然后再执行 EXEC

这个时候客户端会返回 nil,表明拒绝了该事务的执行。

最后

一般不推荐在实际工作中使用 Redis 事务,原因是 Redis 事务有诸多坑:

Redis 的事务支持ACID 吗?

阅读全文