zoukankan      html  css  js  c++  java
  • Redis事务

      Redis事务以MULTI开始,中间添加多种命令,这些命令不会立即执行,而是被放入到一个队列中,当执行EXEC时,队列中的所有命令被依次执行。

      当命令放在MULTI中,但还未执行EXEC时,每个命令返回值为QUEUED,Redis事务将多个命令使用MULTI包括起来,调用EXEC一起执行,减少与客户端之间通信往返次数,提升执行多个命令时的性能

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set key 1
    QUEUED
    127.0.0.1:6379> LPUSH list a
    QUEUED
    127.0.0.1:6379> EXEC
    1) OK
    2) (integer) 1
    127.0.0.1:6379> keys *
    1) "list"
    2) "key"
    127.0.0.1:6379> 

      从2.6.5版本开始,在执行EXEC之前,redis命令在加入队列时,如果出现错误(一般为语法错误),则执行EXEC时,该事务不会被执行,并自动丢弃

    127.0.0.1:6379> FLUSHALL
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> SET flag 1
    QUEUED
    127.0.0.1:6379> LPUSH list a
    QUEUED
    127.0.0.1:6379> LPUSH list
    (error) ERR wrong number of arguments for 'lpush' command
    127.0.0.1:6379> EXEC
    (error) EXECABORT Transaction discarded because of previous errors.
    127.0.0.1:6379> keys *
    (empty list or set)  ## 正确的脚本也未执行,当前事务被丢弃
    127.0.0.1:6379> 

      在2.6.5版本之前,执行MULTI之后,EXEC之前发生错误时,当执行EXEC命令,redis忽略掉错误命令,执行正确的命令。

      在EXEC执行之后发生错误,其他正确的命令会被执行,redis不会回滚

    127.0.0.1:6379> FLUSHALL
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set mykey 1
    QUEUED
    127.0.0.1:6379> LPUSH mykey 12
    QUEUED
    127.0.0.1:6379> EXEC
    1) OK
    2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
    127.0.0.1:6379> keys *
    1) "mykey"      ## 正确命令被执行,错误的命令被丢弃
    127.0.0.1:6379> 

      Redis不支持事务回滚,官网给出了两点理由

    1、redis命令只有两个错误会出现,一个为错误的语法结构,一个为对数据类型使用错误的方法处理,如上例中使用LPUSH操作字符串类型的mykey。这两个问题在开发环境自测的时候就能够发现。

    2、redis内部的结构简单,而且速度更快,因为它不需要回滚功能。

      DISCARD命令可用于终止当前事务并丢弃,也即是清空队列中的命令。该命令必须应用在MULTI命令中

    127.0.0.1:6379> FLUSHALL
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set key v
    QUEUED
    127.0.0.1:6379> set mykey 2
    QUEUED
    127.0.0.1:6379> LPUSH list aa
    QUEUED
    127.0.0.1:6379> DISCARD
    OK
    127.0.0.1:6379> EXEC
    (error) ERR EXEC without MULTI     ## 已经不再事务范围之内,也即是当前事务已经在执行DISCARD的时候结束
    127.0.0.1:6379>

      以上为redis简单的事务操作,但以上存在数据安全问题

      假设小王暑假打工赚了一百块钱,存了起来,但由于小王所在地的一些方面的原因,钱放进去,但还未执行EXEC

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> SET money 100
    QUEUED
    127.0.0.1:6379> 

      此时小王妈妈去银行给小王汇过来1000元,并且营业员服务周到,各种硬件完备,很快就办完了业务

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set money 1000
    QUEUED
    127.0.0.1:6379> EXEC
    1) OK
    127.0.0.1:6379> get money
    "1000"
    127.0.0.1:6379> 

      此时小王的汇款也结束了,(执行了EXEC)

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> SET money 100
    QUEUED
    127.0.0.1:6379> EXEC
    1) OK
    127.0.0.1:6379> get money
    "100"
    127.0.0.1:6379> 

      平白无故丢了一千大洋,还得上十年学,十个暑假才能赚回来这些钱,很心塞。小王的问题也有办法解决,那就是在redis 2.2及以后版本之后引入的WATCH命令

      小王再次存钱卡主

    127.0.0.1:6379> FLUSHALL
    OK
    127.0.0.1:6379> WATCH money    ### 监控money
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set money 100
    QUEUED

      小王的妈妈依然是去银行转钱给小王,效率依然杠杠的

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set money 1000
    QUEUED
    127.0.0.1:6379> EXEC
    1) OK
    127.0.0.1:6379> get money
    "1000"
    127.0.0.1:6379> 

      小王存的钱开始被写入

    127.0.0.1:6379> FLUSHALL
    OK
    127.0.0.1:6379> WATCH money
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set money 100
    QUEUED
    127.0.0.1:6379> EXEC
    (nil)
    127.0.0.1:6379> get money
    "1000"
    127.0.0.1:6379> 

      小王存钱没有成功,查看了下余额,发现已经有1000大洋了,那么这一百块就可以去挥霍了,吃饱喝足,网吧包夜走起。。。

      WATCH命令是一种乐观锁的实现,基于CAS(check and set,在java的JUC下atomic中,一些Atomic开头的类,也使用了CAS原理,只不过在java中被称为compare and set,但大致意思是一样的)。watch用于监控某个key是否发生了改变,如果在一个事务中,某个key在设置参数之后,在执行exec之前,其他客户端修改了该key,则该事务将返回null。

      1、watch必须与multi一起使用,才会发生作用,并且其必须在multi之前执行

      2、watch监控的元素在当前事务提交之前发生变化(另一个事务执行了exec),则无论当前事务中有多少命令,全部失败。

      3、watch监控的元素在当前事务提交之前,被放入到另外一个事务的队列中,但并未执行exec,则当前事务可正常提交

      4、watch监控的元素,被另外一个客户端在非MULTI包括的命令中修改,则无论当前事务中有多少命令,也将全部失败

  • 相关阅读:
    元组-琢磨已久的购物车程序
    学习使我充实自己-列表具备的功能
    很高兴今天用PYTHON3写了三级菜单程序!
    python内建模块shlex将普通字符串编码成符合linux shell的字符串
    HTTPS能登陆,HTTP不行
    linux shell判断输入的是哪个不可见字符,例如^X(Ctrl-X)
    TI CC3200做ETSI EN 300 328 认证
    使用systemd-resolved的系统中DNS来源优先级
    systmed-timesyncd中NTP服务器地址来源优先级
    markdown的简单应用实例
  • 原文地址:https://www.cnblogs.com/qq931399960/p/10556699.html
Copyright © 2011-2022 走看看