• Redis 事务


    Redis 事务

    Redis 事务:一次执行多个命令

    Redis事务工作特点:

    • 批量操作放入队列缓存。(执行有顺序)
    • 事务中任意命令执行失败,其余的命令依然被执行。(不保证原子性)
    • 在事务执行过程,其他命令请求不会插入到事务执行命令序列中。(排他性)

    三个阶段:

    • 开始事务。(multi)
    • 命令入队。
    • 执行事务。(exec)

    实例

    127.0.0.1:6379> multi #开启事务
    OK
    
    ########## 命令入队 开始##################
    127.0.0.1:6379(TX)> set k1 v1
    QUEUED
    127.0.0.1:6379(TX)> set k2 v2
    QUEUED
    127.0.0.1:6379(TX)> get k1
    QUEUED
    127.0.0.1:6379(TX)> set k3 v3
    QUEUED
    ########### 命令入队 结束 #################
    
    127.0.0.1:6379(TX)> exec # 执行事务
    1) OK
    2) OK
    3) "v1"
    4) OK

    放弃事务

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> set k4 v4
    QUEUED
    127.0.0.1:6379(TX)> set k5 v5
    QUEUED
    127.0.0.1:6379(TX)> discard #取消事务
    OK
    127.0.0.1:6379> get k4 ####取消执行事务中所有命令,k4就会没值
    (nil)

    命令有误,事务中所有命令都不执行

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> set k1 v1
    QUEUED
    127.0.0.1:6379(TX)> getset k2 #命令错误
    (error) ERR wrong number of arguments for 'getset' command
    127.0.0.1:6379(TX)> set k3 v3
    QUEUED
    127.0.0.1:6379(TX)> exec
    (error) EXECABORT Transaction discarded because of previous errors.

    运行时异常

    127.0.0.1:6379> set k1 v1 
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> INCR k1 #k1自加一,必须时数值,有错误,不影响其他命令执行
    QUEUED
    127.0.0.1:6379(TX)> set k2 v2 
    QUEUED
    127.0.0.1:6379(TX)> exec
    1) (error) ERR value is not an integer or out of range
    2) OK
    127.0.0.1:6379> get k2
    "v2"

    Redis 事务--锁

    Watch:相当于乐观锁

    通过监视key的值是否改变来决定事务能否正常提交

    实例

    正常执行

    127.0.0.1:6379> set money 100
    OK
    127.0.0.1:6379> set out 0
    OK
    127.0.0.1:6379> watch money #监视money
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> decrby money 20
    QUEUED
    127.0.0.1:6379(TX)> incrby out 20
    QUEUED
    127.0.0.1:6379(TX)> exec #正常执行
    1) (integer) 80
    2) (integer) 20

    事务正常执行完成后,watch监视结束

    多线程操作

    127.0.0.1:6379> watch money
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> DECRBY money 50
    QUEUED
    127.0.0.1:6379(TX)> INCRBY out 50
    QUEUED
    127.0.0.1:6379(TX)> 

    事务没有执行,另一个线程修改了监视的key

    执行事务

    127.0.0.1:6379(TX)> exec #执行失败
    (nil)

    重新执行事务,使用UNWATCH命令(用于取消 WATCH 命令对所有 key 的监视)来保证下一个事务的执行不会受到影响

    127.0.0.1:6379> watch money #开启监视
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> DECRBY money 50
    QUEUED
    127.0.0.1:6379(TX)> INCRBY out 50
    QUEUED
    127.0.0.1:6379(TX)> exec # 执行之前,另一个线程执行了 set money 200
    (nil)
    127.0.0.1:6379> UNWATCH  #取消 WATCH 命令对所有 key 的监视
    OK
    127.0.0.1:6379> WATCH money #开启监视
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> DECRBY money 50
    QUEUED
    127.0.0.1:6379(TX)> INCRBY out 50
    QUEUED
    127.0.0.1:6379(TX)> exec
    1) (integer) 150
    2) (integer) 50

    分布式锁(setnx)

    利用setnx命令的特征(存在Key则返回设置失败,不存在Key则返回设置成功),并通过del命令释放锁。

    127.0.0.1:6379> set num 10
    OK
    127.0.0.1:6379> setnx lock-num 2 #设置key
    (integer) 1
    127.0.0.1:6379> incrby num -1
    (integer) 9
    127.0.0.1:6379> del lock-num #释放,如果不释放的话,就无法再次通过setnx设置key
    (integer) 1
    127.0.0.1:6379> setnx lock-num 1 
    (integer) 1
    127.0.0.1:6379> setnx lock-num 1
    (integer) 0

    使用setnx可能会出现忘记释放的情况,需要针对key设置有效时间

    • expire lock-key second
    • pexpire lock-key milliseconds
    127.0.0.1:6379> setnx lock-num 1
    (integer) 0
    127.0.0.1:6379> expire lock-num 1
    (integer) 1
    127.0.0.1:6379> setnx lock-num 1
    (integer) 1

     由于操作通常都是微秒或毫秒级,因此该锁定时间不宜设置过大。具体时间需要业务测试后确认。

     例如:持有锁的操作最长执行时间127ms,最短执行时间7ms。

     测试百万次最长执行时间对应命令的最大耗时,测试百万次网络延迟平均耗时

     锁时间设定推荐:最大耗时*120%+平均网络延迟*110%

     如果业务最大耗时<<网络平均延迟,通常为2个数量级,取其中单个耗时较长即可

  • 相关阅读:
    vue 无缝无限滚动横条实现
    小程序 recycle-view 个人demo
    js 笔记
    java整理的一些面试资料
    使用js获取浏览器地址栏里的参数
    java面试题
    sql中索引不会被用到的几种情况
    常用linux命令
    shiro登录成功之后跳转原路径
    springboot 整合 mongodb实现 批量更新数据
  • 原文地址:https://www.cnblogs.com/WarBlog/p/15245561.html
Copyright © 2020-2023  润新知