Redis 事务

发布时间 2023-09-29 18:29:18作者: 我们都是小行星

Redis 事务

Redis 中的事务是通过使用 MULTI、EXEC、DISCARD 和 WATCH 命令实现的。以下是这些命令的说明:

  1. MULTI:用于标记事务的开始。在执行 MULTI 后,所有后续的命令都将被认为是事务的一部分。

  2. EXEC:用于执行之前标记的事务。Redis 将按顺序执行事务中的所有命令。

  3. DISCARD:用于取消事务,清空事务队列,并释放与事务关联的任何资源。

  4. WATCH:用于监视一个或多个键,以便在事务执行期间检测到键的变化。如果在 EXEC 执行之前被监视的键发生了变化,事务将被取消。

在 Redis 中,事务是一组命令的集合,这些命令将按顺序执行并原子地提交或回滚。Redis 事务使用 MULTI、EXEC、WATCH、DISCARD 等命令实现。

当客户端发送 MULTI 命令时,Redis 将进入事务模式,并将所有后续命令放入一个队列中,直到客户端发送 EXEC 命令。在 MULTI 和 EXEC 之间执行的所有命令都不会立即执行,而仅会进入事务队列中等待执行。只有在执行 EXEC 命令时,Redis 才会遍历事务队列并以原子方式执行其中的所有命令。

因此,在事务的队列期间,Redis 不会阻塞其他客户端请求。但是事务中的命令如果太多的话,那么在执行的时候会因为单线程而让其他的命令处于等待中,造成阻塞。所以事务中的命令尽量少一些。

正常执行

127.0.0.1:6379> multi 
OK
127.0.0.1:6379> set aa aa
QUEUED
127.0.0.1:6379> set aaa aaa
QUEUED
127.0.0.1:6379> exec

1) OK
2) OK
  127.0.0.1:6379> get aa
  "aa"
  127.0.0.1:6379> get aaa
  "aaa"

 

 

语法出错

语法出错能回滚

127.0.0.1:6379> set aa aa
OK
127.0.0.1:6379> set aaa aaa
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set aa
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> set aaa bbb
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get aaa
"aaa"

 

 

命令出错

aa的值是字符串,不能INCR ,但是能继续执行后续的命令

127.0.0.1:6379> set aa aa
OK
127.0.0.1:6379> set aaa aaa
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> INCR aa
QUEUED
127.0.0.1:6379> set aaa bbb
QUEUED
127.0.0.1:6379> exec

1) (error) ERR value is not an integer or out of range
2) OK
  127.0.0.1:6379> get aa
  "aa"
  127.0.0.1:6379> get aaa
  "bbb"
 

 

 

DISCARD命令

127.0.0.1:6379> set aa aa
OK
127.0.0.1:6379> set aaa aaa
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set aa 11
QUEUED
127.0.0.1:6379> set aaa 111
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> get aaa
"aaa"

 

 

多事务

客户端1:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set aa 11
QUEUED
127.0.0.1:6379> set aaa 111
QUEUED
127.0.0.1:6379> exec     步骤1

1) OK
2) OK
  127.0.0.1:6379> get aa
  "11"
  127.0.0.1:6379> get aaa
  "111"
  127.0.0.1:6379>

 

客户端2

127.0.0.1:6379> multi 
OK
127.0.0.1:6379> set aa 22
QUEUED
127.0.0.1:6379> set aaa 222
QUEUED
127.0.0.1:6379> exec       步骤2

1) OK
2) OK
  127.0.0.1:6379> get aa
  "22"
  127.0.0.1:6379> get aaa
  "222"

 

这里的步骤1先于步骤2执行

 

watch命令

客户端1

127.0.0.1:6379> get aa
"aa"
127.0.0.1:6379> get aaa
"aaa"
127.0.0.1:6379> watch aa   步骤1
OK
127.0.0.1:6379> MULTI   步骤2
OK
127.0.0.1:6379> set aa 11   步骤3
QUEUED
127.0.0.1:6379> set aaa 111 步骤4
QUEUED
127.0.0.1:6379> exec   步骤6
(nil)
127.0.0.1:6379> get aa
"99"
127.0.0.1:6379> get aaa
"aaa"

客户端2

127.0.0.1:6379> set aa 99   步骤5
OK
127.0.0.1:6379> get aa
"99"

这里的步骤345的顺序可以调换不影响结果,客户端1的执行要回滚

 

 

多客户端watch

客户端1

127.0.0.1:6379> WATCH aa
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set aa 11
QUEUED
127.0.0.1:6379> set aaa 111   步骤1
QUEUED
127.0.0.1:6379> exec

1) OK
2) OK

 

客户端2

127.0.0.1:6379> WATCH aa
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set aa 22
QUEUED
127.0.0.1:6379> set aaa 222     步骤2
QUEUED
127.0.0.1:6379> exec
(nil)

客户端3

127.0.0.1:6379> get aa
"11"
127.0.0.1:6379> get aaa
"111"

 

客户端1先执行到步骤1,然后客户端2执行到步骤2,

再执行客户端1exec,返回结果ok

客户端2exec,返回结果nil

说明客户端2回滚了。

 

阻塞

在Redis中,DEBUG SLEEP命令可以用于模拟阻塞的效果。该命令会使当前客户端线程休眠指定的时间。

下面是一个示例,演示如何使用DEBUG SLEEP命令创建一个阻塞时间较长的事务:

客户端1

MULTI
SET key1 value1
DEBUG SLEEP 10
SET key2 value2
EXEC

这时如果有客户端2查询的话,会阻塞等待客户端1的命令执行结束。

 

 

关于回滚

redis的回滚可以理解为取消exec。

在事务中,语法出错导致整个事务无法exec。

但是语法没有问题,命令错误的话是可以 继续执行完整个事务的。