NoSQL数据库之Redis2
创始人
2024-03-01 22:34:47
0

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

示例:

SET Jack 10SET Rose 20# Jack 给 Rose 转账 5 块钱# 开启事务
MULTIDECRBY Jack 5INCRBY ROSE 5EXEC

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

(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 keyERRORCOMMAND keyEXEC

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

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

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

MULTISET key 1SADD key 2SET key 3EXEC

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

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

事务中的 WATCH 命令

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

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

# 开启事务
MULTI# 假设里面有 100 元
SET balance 100# 拿了瓶水
SET balance 3# 拿了包烟
SET balance 20

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

# 开启事务
MULTI# 买了 10 斤苹果
SET balance 100EXEC

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

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

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

WATCH 相关命令如下:

# 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
WATCH key [key ...]# 取消 WATCH 命令对所有 key 的监视。
# 如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。
UNWATCH
SET balance 100WATCH balanceDECRBY balance 30MULTIDECRBY balance 10EXECGET balance # 70

如果在执行 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 日志文件保存到硬盘中,并在服务器启动时,通过重新执行这些命令来还原数据集。

相关内容

热门资讯

MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
操作系统面试题(史上最全、持续... 尼恩面试宝典专题40:操作系统面试题(史上最全、持续更新)...
Android---Banne... 轮播图是一种很常见的UI。Banner框架能够帮助我们快速开发,完成首页轮播图效果的需...
python -- PyQt5... 控件2 本章我们继续介绍PyQt5控件。这次的有 QPixmap , QLineEdi...
Mysql SQL优化跟踪来看... 背景 使用索引字段进行筛选数据时,explain查询语句发现MySQL居然没有使用索...
UG 6.0软件安装教程 UG 6.0软件安装教程 软件简介: UG 6.0是目前网络最好用、使用最为广泛的大型...
HTML静态网页作业——关于我... 家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法,如盒子的嵌套、浮动、ma...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
NoSQL数据库之Redis2 Redis 事务 事务的基础概念 关于事务最常见的例子就是银行转账,A 账户给 B 账...
Spring Security... 前言 在 Spring Security 中,默认的登陆方式是以表单形式进行提交参数的...