Redis - 事务

网友投稿 772 2022-10-25

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

Redis - 事务

为了保障连续多个操作的原子性,数据库通常都会有事务支持,Redis 也不例外。

MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。事务可以一次执行多个命令, 并且带有以下两个重要的保证:

事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行,不会被其他客户端发送来的命令请求所打断。事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

EXEC 命令负责触发并执行事务中的所有命令:

如果客户端在使用 MULTI 开启了一个事务之后,却因为断线而没有成功执行 EXEC ,那么事务中的所有命令都不会被执行。另一方面,如果客户端成功在开启事务之后执行 EXEC ,那么事务中的所有命令都会被执行。

使用示例

MULTI 命令用于开启一个事务,它总是返回 OK 。MULTI 执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当执行 EXEC 命令,队列中的命令才会被执行。EXEC 命令的回复是一个数组,数组中的每个元素都是执行事务中的命令所产生的回复,回复元素的先后顺序和命令发送的先后顺序一致。此外,通过调用 DISCARD,客户端可以清空事务队列,并放弃执行事务。

使用示例:

> multiOK> incr booksQUEUED> incr booksQUEUED> exec(integer) 1(integer) 2

需要注意的是,即使事务中有某条/某些命令执行失败了,事务队列中的其他命令仍然会继续执行。

事务队列

每个 Redis 客户端都有自己的事务状态,这个事务状态保存在客户端状态的 mstate 属性里面:

typedef struct redisClient { // ... // 事务状态 multiState mstate; // ...} redisClient;

事务状态包含一个事务队列和一个已入队命令的计数器(即事务队列的长度):

typedef struct multiState { // 事务队列,FIFO 顺序 multiCmd *commands; // 已入队命令计数 int count;} multiState;

事务队列是一个 multiCmd 类型的数组,multiCmd 结构保存了已入队命令的相关信息,包括指向命令实现函数的指针,命令的参数,以及参数的数量。事务队列以先进先出(FIFO)的方式保存入队的命令:较先入队的命令会被放到数组的前面,而较后入队的命令则会被放到数组的后面。

当一个处于事务状态的客户端向服务器发送 EXEC 命令时:服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命 令所得的结果全部返回给客户端。

WARCH

WATCH 命令是一种乐观锁,它可以在事务开始前监视任意多个变量,当事务执行时,服务器会检查变量是否被修改,如果被修改服务器将拒绝执行事务,并向客户端恢复 nil 代表事务执行失败。

示例:

> watch booksOK> incr books # 被修改了(integer) 1> multiOK> incr booksQUEUED> exec # 事务执行失败(nil)

需要注意的是,Redis 禁止在 MULTI 和 EXEC 之间执行 WATCH 命令,必须在 MULTI 之前监视变量。

每个 Redis 数据库都保存着一个 watched_keys 字典,这个字典的键是某个被 watch 命令监视的数据库键,而字典的值则是一个链表,链表中记录了所有监视相应数据库键的客户端。所有对数据库的修改命令,在执行之后都会检查 watched_keys 字典,查看是否有客户端正在监视被命令修改的键,如果有,则会将监视被修改键的 reids_dirty_cas 标识打开, 表示该客户端的事务安全性已经被破坏。如果在事务提交时,检测到该标识被打开,服务器会拒绝执行事务,以此来保证事务的安全性。

事务的性质

传统的关系型数据库常用 ACID 特性来检验事务的可靠性和安全性。在 Redis 中,事务总具有原子性(Atomicity)、一致性(Consistent)和隔离性(Isalotion),在特定持久化策略下具有持久性(Durable)。

原子性

原子性是指事务中的多个操作要么都执行,要么都不执行。

Redis 不完全满足原子性,Redis 的事务中一组操作如果某个、某些操作失败了,事务队列中的其他命令仍然会继续执行,这是为了保持 Redis 的简单和高效。

一致性

一致性是数据库从一种一致性状态转变到另一种一致性状态,符合数据库本身的定义和要求,不包含非法或无效的数据。

隔离性

隔离性是指各个事务之间不可见,互不影响。

Redis 是单线程执行事务,事务总是串行执行,满足隔离性要求。

持久性

持久性是指事务一经提交,其结果是永久的。

Redis 的持久性取决于持久化策略,前面学习过持久化策略,在 AOF 持久化模式下,而且 appendfsync 选项为 always 时,Redis 可以满足持久性。

但是,如果是基于主从模式的,即使是像上面那样设置也无法完全保证持久性。当发生主从切换,主服务器将指令没有完全同步,就可能导致数据丢失,导致无法满足持久性要求。

文章同步 github。

地址:github.com/lazecoding/Note/blob/main/note/articles/redis/事务.md

上一篇:北京对“健康宝”加强压力测试和系统运行维护,确保正常运行
下一篇:如何选择靠谱的Java大数据培训机构?
相关文章

 发表评论

暂时没有评论,来抢沙发吧~