• NoSQL数据库之Redis2


    Redis 事务

    事务的基础概念

    关于事务最常见的例子就是银行转账,A 账户给 B 账户转账一个亿 (T1),买一块地盖房子。在这种交易的过程中,有几个问题值得思考:

    • 如何同时保证上述交易中,A账户总金额减少一个亿,B账户总金额增加一个亿? A
    • A账户如果同时在和C账户交易(T2),如何让这两笔交易互不影响? I
    • 如果交易完成时数据库突然崩溃,如何保证交易数据成功保存在数据库中? D
    • 如何在支持大量交易的同时,保证数据的合法性(没有钱凭空产生或消失) ? C

    要保证交易正常可靠地进行,数据库就得解决上面的四个问题,这也就是事务诞生的背景,它能解决上面的四个问题,对应地,它拥有四大特性(ACID)。
    在这里插入图片描述

    • 原子性(Atomicity): 事务要么全部完成,要么全部取消。 如果事务崩溃,状态回到事务之前(事务回滚)。

    • 隔离性(Isolation): 如果2个事务 T1 和 T2 同时运行,事务 T1 和 T2 最终的结果是相同的,不管 T1和T2谁先结束。

    • 持久性(Durability): 一旦事务提交,不管发生什么(崩溃或者出错),数据要保存在数据库中。

    • 一致性(Consistency): 只有合法的数据(依照关系约束和函数约束)才能写入数据库。

    Redis 中的事务

    # 标记一个事务块的开始
    # 事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行
    MULTI
    
    # 执行所有事务块内的命令。
    EXEC
    
    # 取消事务,放弃执行事务块内的所有命令。
    DISCARD
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    示例:

    SET Jack 10
    
    SET Rose 20
    
    # Jack 给 Rose 转账 5 块钱
    
    # 开启事务
    MULTI
    
    DECRBY Jack 5
    
    INCRBY ROSE 5
    
    EXEC
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    上面的代码演示了事务的使用方式。

    (1)开始事务:首先使用 MULTI 命令告诉 Redis:“下面我发给你的命令属于同一事务,你先不要执行,而是把它们暂时存起来”。Redis 回答:“OK”

    (2)命令入队:而后我们发送了两个命令来实现相关操作,可以看到 Redis 遵守了承诺,没有执行这些命令,而是返回 QUEUED 表示这两条命令已经进入等待执行的事务队列中了

    (3)执行事务:当把所有要在同一事务中执行的命令都发给 Redis 后,我们使用 EXEC 命令告诉 Redis 将等待执行的事务队列中的所有命令按照发送的顺序依次执行。EXEC 命令的返回值就是这些命令的返回值组成的列表,返回值顺序和命令的顺序相同。

    (4)如果想要取消事务,则执行 DISCARD 命令。

    Redis 保证了一个事务中的所有命令要么都执行,要么都不执行。如果在发送 EXEC 命令前客户端掉线了,则 Redis 会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了 EXEC 命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为 Redis 中已经记录了所有要执行的命令。

    除此之外,Redis 的事务还能保证一个事务内的命令依次执行而不被其它命令插入。试想客户端 A 需要执行几条命令,同时客户端 B 发送了一条命令,如果不适用事务,则客户端 B 的命令可能会插入到客户端 A 的几条命令中执行。如果不希望发送这种情况,也可以使用事务。

    事务中的错误处理

    如果一个事务中的某个命令执行出错,Redis 会怎么处理呢?要回答这个问题,首先需要知道什么原因导致命令执行出错。

    (1)语法错误。语法错误指命令不存在或命令参数的个数不对。比如:

    MULTI
    
    # 正确的命令
    SET key value
    
    # 错误的命令
    SET key
    
    ERRORCOMMAND key
    
    EXEC
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    跟在 MULTI 命令后执行了 3 个命令:

    • 一个正确的命令,成功的加入了事务队列
    • 其余两个命令都有语法错误
      而只要有一个命令有语法错误,执行 EXEC 命令后 Redis 就会直接返回错误,连语法正确的命令也不会执行。

    (2)运行错误。运行错误指在命令执行时出现的错误,比如使用散列类型的命令操作集合类型的键,这种错误在实际执行之前 Redis 是无法发现的,所以在事务里这样的命令是会被 Redis 接受并执行的。如果事务里的一条命令出现了运行错误,事务里其它的命令依然会继续执行

    MULTI
    
    SET key 1
    
    SADD key 2
    
    SET key 3
    
    EXEC
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Redis 事务没有关系数据库事务提供的回滚(rollback)功能。为此开发者必须在事务执行出错后自己收拾剩下的摊子(将数据库复原回事务执行前的状态等)。

    不过由于 Redis 不支持回滚功能,也使得 Redis 在事务上可以保持简洁和快速。此外回顾刚才提到的会导致事务执行失败的两种错误,其中语法错误完全可以在开发时找出并解决,另外如果能够很好的规划数据库的使用,是不会出现如命令与数据类型不匹配这样的运行时错误的。

    事务中的 WATCH 命令

    关于 WATCH 命令,我们来一个生活中的例子比较好理解。

    假设我的银行卡有 100 元,此时我去商店买东西

    # 开启事务
    MULTI
    
    # 假设里面有 100 元
    SET balance 100
    
    # 拿了瓶水
    SET balance 3
    
    # 拿了包烟
    SET balance 20
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    我的银行卡除了我自己消费使用,还绑定了我媳妇儿的支付宝,如果我在消费的时候,她也消费了会怎么样?

    # 开启事务
    MULTI
    
    # 买了 10 斤苹果
    SET balance 100
    
    EXEC
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这时候我媳妇在超市直接刷了 100,此时余额不足的我还在挑口香糖…

    针对于上面的场景,我们可以使用 Redis 事务中提供的 WATCH 功能来解决这个问题。

    WATCH 定义:监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

    WATCH 相关命令如下:

    # 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
    WATCH key [key ...]
    
    # 取消 WATCH 命令对所有 key 的监视。
    # 如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。
    UNWATCH
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    SET balance 100
    
    WATCH balance
    
    DECRBY balance 30
    
    MULTI
    
    DECRBY balance 10
    
    EXEC
    
    GET balance # 70
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令被执行了的话,那么会自动取消 WATCH。

    如果需要手动停止 WATCH 则可以可以使用 UNWATCH 命令,UNWATCH 命令会取消 WATCH 命令对所有 key 的监视。

    参考链接

    • https://zhuanlan.zhihu.com/p/43493165
    • https://xie.infoq.cn/article/84baa7fa9c2c3d3698a601def

    Redis持久化

    Redis 的强劲性能很大程度上是由于其将所有数据都存储在内存中,然而当 Redis 重启或宕机后,所有存储在内存中的数据就会丢失。在一些情况下,我们会希望 Redis 在重启后能够保证数据不丢失。

    这时我们希望 Redis 能将数据从内存中以某种形式同步到硬盘中,使得重启后可以根据硬盘中的记录恢复数据。这一过程就是持久化。

    Redis 提供了两种持久化方案:

    • RDB 持久化,根据指定的规则“定时”将内存中的数据存储在硬盘上,在重启之后读取硬盘上的 .rdb 快照文件将数据恢复到内存中。
    • AOF 持久化:AOF 持久化记录服务器执行的所有写操作命令形成 .aof 日志文件保存到硬盘中,并在服务器启动时,通过重新执行这些命令来还原数据集。
  • 相关阅读:
    表情和微表情数据集总结
    YOLOv5算法改进(12)— 主干网络介绍(EfficientNetv2、Swin Transformer和PP-LCNet)
    APM性能监测工具skywalking——k8s从入门到高并发系列教程(十三)
    APS高级排程具有哪些功能?
    RSA的C++语言描述简单实现
    GoFrame+Vue+ElementUI学习入门基础框架搭建
    [附源码]Python计算机毕业设计SSM京东仓库管理系统(程序+LW)
    Android混淆笔记
    Java核心篇,二十三种设计模式(十四),行为型——命令模式
    使用dateutil的parser.parse()格式化时间对象
  • 原文地址:https://blog.csdn.net/qq_42308316/article/details/128105876