回答
ACID,即 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),Redis 事务在某种程度上支持 ACID,但又不完全支持,具体情况下:
- 原子性(Atomicity):保证部分原子性,由于不支持回滚,导致部分场景下无法保证原子性。
- 一致性(Consistency):Redis 保证一致性。
- 隔离性(Isolation):Redis 保证部分隔离性,如果不使用 WATCH,无法做到绝对的隔离。
- 持久性(Durability):依靠持久化方式,但无论哪种方式都无法保证绝对的持久性。所以 Redis 不保证持久性。
详解
原子性支持
原子性是指单个事务是一个不可分割的最小工作单元,整个事务中的所有操作要么全部成功 Commit,要么全部失败Rollback。
Redis 事务是原子性是部分支持。
Redis 支持原子性情况
Redis 通过 MULTI
命令开始一个事务,之后跟随的所有命令都会被序列化并放入事务队列中,直到 EXEC
命令被调用,这时所有的命令按照 FIFO 的顺序依次执行,这种方式保证了事务中的命令作为一个整体原子地执行。这种情况保证原子性。
如果客户端发送的命令本身就有错误,例如语法错误,被 Redis 在执行之前识别了,这个时候我们如果执行 EXEC
命令,Redis 会拒绝执行所有命令。这种情况保证原子性。
Redis 不支持原子性情况
如果我们输入的命令,Redis 服务器在执行 EXEC
前没有识别出来,例如命令和操作的数据类型不匹配,这种情况,在执行 EXEC
时,Redis 执行这些错误的命令时是会报错,但是,Redis 依然会把正确的命令执行完,不会回滚!这种情况不保证原子性。
分情况
在执行 EXEC
命令时,Redis 服务器发生了故障,导致事务执行失败。这种情况分为以下两种情况:
- 如果我们开启了 AOF 日志,那么,就只会有该事务的部分操作被记录到了 AOF 日志中,这个时候我们使用
redis-check-aof
工具检查 AOF 日志文件,该工具可以把未完成的事务操作从 AOF 文件中抹除掉,这样一来,我们使用 AOF 恢复 Redis 实例后,事务操作不会再被执行,从而保证了原子性。这种情况保证原子性。 - 如果我们没有开启 AOF 日志,那么当 Redis 服务重启后,数据也就无法恢复了。这种情况不保证原子性。
总结
- 所有命令成功执行,Redis 保证它们作为一个整体原子性地执行。保证原子性。
- 命令入事务队列报错,Redis 会拒绝事务的执行。保证原子性。
- 命令入事务队列成功,但在执行时报错,这时 Redis 会执行完所有命令,不会回滚。不保证原子性。
- Redis 在执行命令时,若 Redis 服务器发生故障,如果开启了 AOF 日志,则保证原子性,否则不保证。
一致性支持
**一致性是指在事务开始之前和完成之后,数据库必须从一个一致的状态转换到另一个一致的状态。**一致性确保了数据库的所有数据规则都得到遵守,包括数据的完整性约束、数据库自身定义的规则、业务规则等。一致性意味着任何事务都不会破坏这些规则,确保数据的准确性和有效性。
Redis 保证每个单独的命令执行都是原子的,并且遵循数据类型所定义的规则,对于列表、集合、有序集合等复杂数据类型的操作,Redis 保证每个操作的一致性。这种情况保证一致性。
Redis 强制执行数据类型约束,如果我们尝试对一个特定类型的数据执行不支持的操作,例如对一个存储字符串的键执行列表操作,这是 Redis 会报错。这种情况保证一致性。
若命令在入事务队列时报错,Redis 会拒绝事务的执行。这种情况保证一致性。
若命令在入事务队列不报错,但执行命令时报错,这个时候 Redis 会执行所有正确的命令,错误的命令支持出错。这种情况保证一致性。
若在 EXEC
命令执行时实例发生故障,分为如下几种情况:
- 没有开启 RDB 或者 AOF ,Redis 服务器重启恢复,数据会丢失,数据库状态一致。这种情况保证一致性。
- 若开启了 RDB,由于 RDB 不会在事务执行时执行,所以在 Redis 服务器恢复后,数据会丢失,数据库状态是一致的。这种情况保证一致性。
- 若开启了 AOF,无论事务操作是否已记录到 AOF 日志中,在 Redis 服务恢复后,数据库状态也是一致的。这种情况保证一致性。
隔离性支持
隔离性是指在并发环境下,事务的操作和数据变化对其他并发执行的事务是隔离的,以防止事务之间的相互干扰。隔离性确保了一个事务的中间状态对其他事务是不可见的,从而防止了多个并发事务可能引起的数据不一致问题。
Redis 能够保证事务中的所有命令作为一个整体原子地执行,再加上 Redis 是单线程执行命令的,所以如果并发操作是发生在 EXEC
命令执行后,则可以保证隔离性。
但是如果并发操作发生在 EXEC
命令之前之前,如果我们使用了 WATCH
,则也可以保证隔离性,如果不使用 WATCH
,则无法保证。
WATCH
用于在事务执行之前监控一个或多个 key 的变化情况,当我们执行 EXEC
后,WATCH
会先检查监控的值是否被其他客户端修改了,如果修改了,在放弃事务的执行,这样就避免了事务的隔离性被破坏。
所以:
- 并发发生在 EXEC 命令执行后,保证隔离性
- 并发发生在 EXEC 命令执行前,需要依靠 WATCH 来保证隔离性。
持久性支持
持久性是指一旦数据库事务成功提交,其所做的更改就会被永久保存在数据库中,即使发生系统崩溃或其他故障,这些更改也不会丢失。
Redis 的持久性靠 RDB 或 AOF 来保证。
- 若 Redis 没有配置 RDB 或 AOF,肯定无法保证持久性。
- 如果 Redis 采用了 RDB 模式。在一个事务开始执行后,如果下一次 RBD 快照还未执行,这时 Redis 服务发生故障,这种情况数据就会丢失,这种情况下,Redis 事务无法保证持久性。
- 如果 Redis 采用 AOF 模式,无论是三种配置中的哪种都无法保证不丢失数据,所以,在这种情况下,Redis 事务也是无法保证持久性的。