Redis的事务

服务器

浏览数:37

2019-10-14

一、是什么

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

二、能干啥

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

三、示例演示

  1. 正常执行

    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
  2. 放弃事务

    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"
  3. 一损俱损

    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)
  4. 冤头债主

    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命令执行的事务都将被放弃

作者:binbin