Table of Contents

一、Redis 事务简介

Redis 通过 MULTI 、 EXEC 、 DISCARD 和 WATCH 等命令来实现事务功能。

MULTI :开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令系列。

EXEC:执行事务中的所有操作命令。

DISCARD:取消事务,放弃执行事务块中的所有命令。

WATCH:监视一个或多个key,如果事务在执行前,这个key(或多个key)被其他命令修改,则事务被中断,不会执行事务中的任何命令。

UNWATCH:取消WATCH对所有key的监视

以下是一个事务执行的过程:

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 11
QUEUED
127.0.0.1:6379> set k2 22
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK

二、事务的实现

  1. 事务开始

    标识符,表示进入事务模式

  2. 命令入队

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

    image-20211209161715299

    事务状态包含一个事务队列,以及一个已入队命令的计数器,也可以说是事务队列的长度:

    image-20211209161811671

    image-20211209161851326

  3. 事务执行

三、WATCH 命令的实现

WATCH 是一个乐观锁,被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。

每个Redis 数据库都保存着一个 watched_keys字典:数据库键与监视键的客户端链表组成的键值对。利用这个字典,可以清楚知道哪些键被监视,以及哪些客户端正在监视这些数据库键。

REDIS_DIRTY_CAS 标识,表示该客户端的事务安全性是否被破坏。

最后判断事务是否安全:

image-20211209163905070

四、事务的 ACID 性质

在 Redis 中,事务总是具有原子性(Atomicity)、一致性(Consistency)和隔离性(Isolation),并且当 Redis 运行在某种特定的持久化模式下时,事务也具有耐久性(Durability)。

4.1 原子性

我们知道事务运行期的错误是不会回滚的,很多文章由此说Redis事务违背原子性的;而官方文档认为是遵从原子性的。

Redis官方文档给的理解是,Redis的事务是原子性的:所有的命令,要么全部执行,要么全部不执行。而不是完全成功。

4.2 一致性

事务具有一致性指的是,如果数据库在执行事务之前是一致的,那么事务执行之后无论事务是否执行成功,数据库也应该仍然是一致的。

  1. 入队错误

    如果一个事务在入队命令的过程中,出现了命令不存在,或者命令的格式不正确等情况,那么Redis 将拒绝执行这个事务。

    image-20211209170105528

  2. 执行错误

    除了入队时可能发送错误以外,事务还可能在执行的过程中发生错误。

    • 执行过程中发生的错误都是一些不能在入队时被服务器发现的错误,这些错误只会在命令实际执行时被触发。
    • 即使在事务的执行过程中发生了错误,服务器也不会中断事务的执行,它会继续执行事务中余下的其他命令,并且已执行的命令不会被出错的命令影响。

    对数据库键执行了错误类型的操作是事务执行期间最常见的错误之一。

  3. 服务器停机

4.3 隔离性

redis事务是严格遵守隔离性的,原因是redis是单进程单线程模式(v6.0之前),可以保证命令执行过程中不会被其他客户端命令打断。

但是,Redis不像其它结构化数据库有隔离级别这种设计。

4.4 耐久性

持久化配置模式不同,对耐久性的保证也不同。