乐趣区

Redis的事务

一、是什么

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

二、能干啥

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

三、示例演示

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

退出移动版