Redis如何实现事务?
事务的执行过程包含三个步骤,Redis 提供了 MULTI、EXEC 两个命令来完成这三个步骤。
- 第一步,客户端要使用一个命令显式地表示一个事务的开启。在 Redis 中,这个命令就是MULTI。
- 第二步,客户端把事务中本身要执行的具体操作(例如增删改数据)发送给服务器端。这 些操作就是 Redis 本身提供的数据读写命令,例如 GET、SET 等。不过,这些命令虽然被 客户端发送到了服务器端,但 Redis 实例只是把这些命令暂存到一个命令队列中,并不会 立即执行。
- 第三步,客户端向服务器端发送提交事务的命令,让数据库实际执行第二步中发送的具体 操作。Redis 提供的 EXEC 命令就是执行事务提交的。当服务器端收到 EXEC 命令后,才 会实际执行命令队列中的所有命令。
好了,通过使用 MULTI 和 EXEC 命令,我们可以实现多个操作的共同执行,但是这符合事 务要求的 ACID 属性吗?
原子性
如果事务正常执行,没有发生任何错误,那么,MULTI 和 EXEC 配合使用,就可以保证多 个操作都完成。但是,如果事务执行发生错误了,原子性还能保证吗?
- 第一种情况是,在执行 EXEC 命令前,客户端发送的操作命令本身就有错误(比如语法错 误,使用了不存在的命令),在命令入队时就被 Redis 实例判断出来了。此时,能够保障原子性,因为后续的命令都会被放弃。
- 第二种情况,错误发生在命令执行时,虽然 Redis 会对错误命令报错,但还是会把正确的命令执 行完。在这种情况下,事务的原子性就无法得到保证了。
一致性
- 命令在执行前报错,所以命令都不会被执行,一致性可以保障;
- 命令执行中报错,报错的命令不被执行,正确的命令会被执行,严格来说,业务的一致性被破坏了。
隔离性
- 并发操作在 EXEC 命令前执行,此时,隔离性的保证要使用 WATCH 机制来实现,否则隔离性无法保证;
- 并发操作在 EXEC 命令后执行,此时,隔离性可以保证,因为只有一个线程执行。
WATCH 机制的作用是,在事务执行前,监控一个或多个键的值变化情况,当事务调用EXEC 命令执行时,WATCH 机制会先检查监控的键是否被其它客户端修改了。如果修改了,就放弃事务执行,避免事务的隔离性被破坏。然后,客户端可以再次执行事务,此时,如果没有并发修改事务数据的操作了,事务就能正常执行,隔离性也得到了保证。
持久性
数据是否持久化保存完全取决于 Redis 的持久化配置模式。
- 如果是RDB模式,,那么,在一个事务执行后,而下一次的 RDB 快照还未执行前,如果发生了实例宕机,这种情况下,事务修改的数据也是不能保证持久化的。
- 如果是AOF模式,因为 AOF 模式的三种配置选项 no、everysec 和 always都会存在数据丢失的情况,所以,事务的持久性属性也还是得不到保证。