介绍
Redis为提升性能采用 简单事务,事务没有关系型数据库事务那么复杂,其本质是 一组命令的集合。
事务支持一次执行多个命令,所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
没有回滚:事务中 某个命令执行失败,其余的命令仍会被执行
事务执行前,其他客户端可以修改相关的值
Redis事务的三个阶段:
- 开始事务(multi)
- 命令入队
- 执行事务 或 取消事务
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 可实现回滚操作
- 在
MULTI之前使用WATCH来监控某些键值对 - 然后使用
MULTI命令来开启事务 - 执行数据操作命令,此时这些命令入队列。
- 执行事务
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