一、是什么
可以一次执行多个命令,本质是一组命令的集合,一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞
二、能干啥
一个队列中,一次性,顺序性的执行一系列命令
三、示例演示
-
正常执行
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 k2 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> EXEC // 执行事务 1) OK // 执行结果 2) OK 3) "v2" 4) OK
-
放弃事务
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> set k3 33 QUEUED 127.0.0.1:6379> DISCARD // 放弃事务 OK 127.0.0.1:6379> get k2 // 获取到的还是先前设置的 v2 "v2"
-
一损俱损
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k4 v4 QUEUED 127.0.0.1:6379> setget k5 55 // 命令错误,全都执行不成功 (error) ERR unknown command 'setget' 127.0.0.1:6379> set k6 v6 QUEUED 127.0.0.1:6379> EXEC (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get k4 // 获取的为 nil (nil)
-
冤头债主
127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> INCR k1 // 执行没有报错,运行的时候报错,不影响其他的 QUEUED 127.0.0.1:6379> set k4 v4 QUEUED 127.0.0.1:6379> set k5 v5 QUEUED 127.0.0.1:6379> get k4 QUEUED 127.0.0.1:6379> EXEC 1) (error) ERR value is not an integer or out of range 2) OK 3) OK 4) "v4" // 可以获取到值
四、watch 监控
watch 命令监视一个(或多个)key, 如果在事务执行之前这个(或这些)key 被其他命令所改动,那么事务将被打断
unwatch 取消 watch 命令对所有 key 的监视
-
悲观锁 / 乐观锁 /CAS(Check And Set)
悲观锁
,就是很悲观,每次拿数据都认为别人会修改,多以拿数据前会上锁,这样别人拿数据就会阻塞,直到它拿到锁,传统关系型数据库里用到了很多这种锁机制,如行锁,表锁等,读锁,血锁,都是在操作之前上锁乐观锁
,就是很乐观,每次拿数据都认为别人不会修改,所以不上锁,但更新时会判断一下在此期间有没有人更新过这个数据,可以使用版本号等机制,这样可以提高吞吐量。乐观锁策略:提交版本必须大于记录当前版本才能执行更新
无加塞篡改:
127.0.0.1:6379> set balance 100 // 信用卡余额 100 OK 127.0.0.1:6379> set debt 0 // 信用卡债务 20 OK 127.0.0.1:6379> watch balance // 监控余额 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> EXEC 1) (integer) 80 // 余额减少 20 2) (integer) 20
无加塞篡改:
127.0.0.1:6379> set balance 100 // 信用卡余额 100 OK 127.0.0.1:6379> set debt 0 // 信用卡债务 20 OK 127.0.0.1:6379> watch balance // 监控余额 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> EXEC 1) (integer) 80 // 余额减少 20 2) (integer) 20
有加塞篡改:
开启两个会话窗口
第一个会话窗口 watch 指令执行完,设置余额为 800,最后提交失败,余额变为 800
五、小结
watch 指令,类似乐观锁,事务提交时,如果 key 的值已被别的客户端改变,整个事务都不会被执行
通过 watch 命令在事务执行前监控了多个 keys, 倘若在 watch 之后有任何 key 的值发生变化,exec 命令执行的事务都将被放弃