玩转Redis-事务

概述

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会被序列化,**按顺序地串行化执行而不被其他命令插入,不许加塞。**一个队列中,一次性,顺序性,排他性的执行一系列命令。


常用命令

  • DISCARD:取消事务,放弃执行事务块内的所有命令
  • EXEC:执行所有事务块内的命令
  • MULTI:标记一个事务块的开始
  • UNWATCH:取消WATCH命令对所有key的监视
  • WATCH key[key…]:监视一个或多个命令,如果在事务执行之前这些key被其他命令所改动,那么事务将被打断。

正常执行
127.0.0.1:6379> MULTI //开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get ke
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> EXEC//事务提交
1) OK
2) OK
3) (nil)
4) "v1"
5) OK

放弃事务
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET K2 V3
QUEUED
127.0.0.1:6379> DISCARD //放弃事务
OK
127.0.0.1:6379> get k2
"v2"  //k2value仍然是v2
全体连坐(事务块中一条语句出错则不会执行本次事务)
127.0.0.1:6379> SET K1 V1
OK
127.0.0.1:6379> GET K1
"V1"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET K1 V2
QUEUED
127.0.0.1:6379> SETGET K2
(error) ERR unknown command 'SETGET'
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> MULTI
OK
127.0.0.1:6379> set k1 aa
QUEUED
127.0.0.1:6379> INCR k1 //非数字不能INCR
QUEUED
127.0.0.1:6379> set k2 22
QUEUED
127.0.0.1:6379> set k3 33
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range //报错
3) OK
4) OK

这个场景和前面的“全体连坐”是不同的。前面的"全体连坐场景是在运行时已经报错,之后强制执行旧就导致全体语句不执行",而这个场景在执行的过程中并没有报错。从这点可以看出Redis对事务的支持是部分支持,并没有完全的原子性


Watch监控

关于乐观悲观锁和CAS原理
模拟信用卡刷卡流程

#会话一
127.0.0.1:6379> WATCH balance//Watch需要在事务前执行
OK
#会话一
127.0.0.1:6379> MULTI
OK
#会话一
127.0.0.1:6379> DECRBY balance 20
QUEUED
#会话一
127.0.0.1:6379> INCRBY debt 20
QUEUED
#会话二
127.0.0.1:6379> set balance 800
OK
#会话一
127.0.0.1:6379> exec
(nil)//会话一由于会话二对监视的balance的改动二执行事务失败
127.0.0.1:6379> get balance
"800"

通过Watch命令在事务执行之前监控了多个keys,倘若在watch之后有任何key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务失败
一旦执行了exec后,之前加的监控锁都会被取消掉


小结

事务流程:

  • 开启:以MULTI开始一个事务
  • 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是先放到事务中
  • 执行:由EXEC命令触发事务

特性:

  • 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然被执行,没有回滚
  • 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行。这样也就不存在**“事务内的查询要看到事务里的更新,在事务外的查询不能看到”**这个让人十分头痛的问题
  • 单独的隔离操作:事务中的所有命令都会被序列化,按顺序地执行。事务执行过程中,不会被其他客户端发送来的命令请求所打断

猜你喜欢

转载自blog.csdn.net/weixin_40288381/article/details/88087113