一、是什么

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

二、能干啥

一个队列中,一次性,顺序性的执行一系列命令

三、示例演示

  1. 正常执行

    127.0.0.1:6379> MULTI // 开启事务OK127.0.0.1:6379> set k1 v1 //入队QUEUED127.0.0.1:6379> set k2 v2QUEUED127.0.0.1:6379> get k2QUEUED127.0.0.1:6379> set k3 v3QUEUED127.0.0.1:6379> EXEC //执行事务1) OK // 执行结果2) OK3) "v2"4) OK
  2. 放弃事务

    127.0.0.1:6379> MULTIOK127.0.0.1:6379> set k1 v1QUEUED127.0.0.1:6379> set k2 22QUEUED127.0.0.1:6379> set k3 33QUEUED127.0.0.1:6379> DISCARD //放弃事务OK127.0.0.1:6379> get k2 // 获取到的还是先前设置的v2"v2"
  3. 一损俱损

    127.0.0.1:6379> MULTIOK127.0.0.1:6379> set k4 v4QUEUED127.0.0.1:6379> setget k5 55 //命令错误,全都执行不成功(error) ERR unknown command 'setget'127.0.0.1:6379> set k6 v6QUEUED127.0.0.1:6379> EXEC(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> get k4 // 获取的为nil(nil)
  4. 冤头债主

    127.0.0.1:6379> get k1"v1"127.0.0.1:6379> MULTIOK127.0.0.1:6379> INCR k1 //执行没有报错,运行的时候报错,不影响其他的QUEUED127.0.0.1:6379> set k4 v4QUEUED127.0.0.1:6379> set k5 v5QUEUED127.0.0.1:6379> get k4QUEUED127.0.0.1:6379> EXEC1) (error) ERR value is not an integer or out of range2) OK3) OK4) "v4" // 可以获取到值

四、watch监控

watch命令监视一个(或多个)key,如果在事务执行之前这个(或这些)key 被其他命令所改动,那么事务将被打断
unwatch 取消watch命令对所有key的监视

  • 悲观锁/乐观锁/CAS(Check And Set)
    悲观锁,就是很悲观,每次拿数据都认为别人会修改,多以拿数据前会上锁,这样别人拿数据就会阻塞,直到它拿到锁,传统关系型数据库里用到了很多这种锁机制,如行锁,表锁等,读锁,血锁,都是在操作之前上锁

    乐观锁,就是很乐观,每次拿数据都认为别人不会修改,所以不上锁,但更新时会判断一下在此期间有没有人更新过这个数据,可以使用版本号等机制,这样可以提高吞吐量。乐观锁策略:提交版本必须大于记录当前版本才能执行更新

    无加塞篡改:

    127.0.0.1:6379> set balance 100 //信用卡余额100OK127.0.0.1:6379> set debt 0 //信用卡债务20OK127.0.0.1:6379> watch balance // 监控余额OK127.0.0.1:6379> MULTIOK127.0.0.1:6379> DECRBY balance 20QUEUED127.0.0.1:6379> INCRBY debt 20QUEUED127.0.0.1:6379> EXEC1) (integer) 80 //余额减少202) (integer) 20

    无加塞篡改:

    127.0.0.1:6379> set balance 100 //信用卡余额100OK127.0.0.1:6379> set debt 0 //信用卡债务20OK127.0.0.1:6379> watch balance // 监控余额OK127.0.0.1:6379> MULTIOK127.0.0.1:6379> DECRBY balance 20QUEUED127.0.0.1:6379> INCRBY debt 20QUEUED127.0.0.1:6379> EXEC1) (integer) 80 //余额减少202) (integer) 20

    有加塞篡改:
    开启两个会话窗口

    第一个会话窗口watch指令执行完,设置余额为800,最后提交失败,余额变为800

五、小结

watch指令,类似乐观锁,事务提交时,如果key的值已被别的客户端改变,整个事务都不会被执行
通过watch命令在事务执行前监控了多个keys,倘若在watch之后有任何key的值发生变化,exec命令执行的事务都将被放弃