redis事务(watch、multi、exec、discard、unwatch)

介绍

Redis为提升性能采用 简单事务,事务没有关系型数据库事务那么复杂,其本质是 一组命令的集合。

事务支持一次执行多个命令,所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

没有回滚:事务中 某个命令执行失败,其余的命令仍会被执行

事务执行前,其他客户端可以修改相关的值

Redis事务的三个阶段:

  1. 开始事务(multi)
  2. 命令入队
  3. 执行事务 或 取消事务

Redis事务相关命令:

  • multi:开始事务
  • exec:执行事务
  • discard:取消事务
  • watch:监视
  • unwatch:取消监视

multi

标记一个事务的开始( queued )

multi

注意: 执行 multi 命令后,再执行 数据操作命令,都被放入 队列缓存,并 不会执行
在事务内的查询指令,也会放入到队列中
事务外查询,数据不会发生变化,因为还没有提交事务

exec

执行所有事务块的命令 ( 一旦执行 exec 后,之前加的监控锁都会被取消掉 )

exec

例子

>multi
OK
>set name lilei
QUEUED
>set age 20
QUEUED
exec
1) OK # 说明第一条指定成功
2) OK # 说明第一条指定成功

查看数据:

>get name
>get age

discard

取消事务,放弃事务块中的所有命令

discard

例子

>multi
OK
>set name lucy
QUEUED
>set age 21
QUEUED
discard
OK # 取消成功,数据没有编号

watch

watch key1 key2 ...

监视一或多个key,如果在 事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 )

unwatch

取消watch对所有key的监控

unwatch

事务失败 不会回滚

输入命令时发生错误(如语法错误)

开启事务后,在输入命令时发生错误(如语法错误),导致 事务中断

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 11
QUEUED
127.0.0.1:6379> sets k2 22
(error) ERR unknown command `sets`, with args beginning with: `k2`, `22`, 
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379>

执行时发生错误(如类型错误)

开启事务后,输入命令正确,但执行时发生错误(如类型错误),报错的命令不执行,其他命令正常执行,不会回滚

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 11
QUEUED
127.0.0.1:6379> lpush k2 22
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get k1
"11"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379>

WATCH(可实现回滚操作)

借助 WATCH 可实现回滚操作

  1. 在MULTI之前使用WATCH来监控某些键值对
  2. 然后使用MULTI命令来开启事务
  3. 执行数据操作命令,此时这些命令入队列。
  4. 执行事务EXEC,此时操作如下:
    • 先比WATCH监控的键值对,如果没发生改变,执行事务队列中的命令,提交事务;
    • 如果发生变化,将不会执行事务中的任何命令,同时事务回滚。

执行EXEC后,会取消执行事务前的WATCH命令。

例子

执行客户端A:在事务开始前用WATCH监控k1,MULTI开始事务,修改k1值为12,k2为22

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> WATCH k1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 12
QUEUED
127.0.0.1:6379> set k2 22
QUEUED

执行客户端B:之后修改k1为11,说明事务开始前k1值被改变

127.0.0.1:6379> set k1 11
OK

在执行客户端A:执行EXEC,发回nil,说明事务回滚;查看下k1、k2的值都没有被事务中的命令所改变

127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> get k1
"11"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379>

UNWATCH取消监视所有key

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> WATCH k1
OK
127.0.0.1:6379> set k1 11
OK
127.0.0.1:6379> UNWATCH
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 12
QUEUED
127.0.0.1:6379> set k2 22
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
127.0.0.1:6379> get k1
"12"
127.0.0.1:6379> get k2
"22"
127.0.0.1:6379>

感谢:
https://www.cnblogs.com/fengguozhong/p/12161363.html
https://www.cnblogs.com/DeepInThought/p/10720132.html


原文出处:/show_1EF5oJJdemoL.html