Redis 的事务需要先划分出三个阶段
- 事务开启:使用 MULTI 可以标志着执行该命令的客户端从非事务状态切换至事务状态;
- 命令入队:MULTI开启事务之后,非 WATCH、EXEC、DISCARD、MULTI
等特殊命令,客户端的命令不会被立即执行,而是放入一个事务队列;
如果收到 EXEC 命令,事务队列里的命令将会被执行;
如果收到 DISCARD 命令,则事务被丢弃。
命令入队过程如果出错(如使用了不存在的命令),则事务队列会被拒接执行;
- 执行事务:执行事务期间出现了异常(如命令和操作的数据类型不匹配),事务队列的里的命令还是继续执行下去,直到全部命令执行完,不会回滚。
WATCH 可用于监控 redis 变量值,在命令 EXEC 之前,redis 里的数据是有机会被其他客户端的命令修改的。使用 WATCH
监控的变量被修改后,执行 EXEC 时则会返回执行失败的 nil 回复
从严格意义上来说,Redis 是没有事务的。因为事务必须具备四个特点:
原子性(Atomicity)
一致性(Consistency)
隔离性(Isolation)
持久性(Durability)
Redis 是做不到这四点,只是具备其中一些特征,redis的事务是个伪事务,而且不支持回滚。
原子性
EXEC命令执行前:
在命令入队时就报错,(如内存不足,命令名称错误),redis 就会报错并且记录下这个错误。此时,客户还能继续提交命令操作;等到执行EXEC时,redis 就会拒绝执行所有提交的命令操作,返回事务失败的结果 nil。
EXEC命令执行后:
命令和操作的数据类型不匹配,但 redis 实例没有检查出错误。在执行完 EXEC 命令以后,redis 实际执行这些指令,就会报错。此时事务是不会回滚的,但事务队列的命令还是继续被执行。事务的原子性无法保证。
EXEC执行时发生故障:
如果 redis 开启了 AOF 日志,那么,只会有部分的事务操作被记录到 AOF 日志中。需要使用 redis-check-aof 工具检查 AOF 日志文件,这个工具可以把未完成的事务操作从 AOF 文件中去除。事务的原子性得到保证。
一致性
EXEC命令执行前:
入队报错事务会被放弃执行,具有一致性。
EXEC命令执行后:
实际执行时报错,错误的指令不会执行,正确的指令可以正常执行,一致性可以保证。
EXEC执行时发生故障:
RDB 模式,RDB 快照不会在事务执行时执行,事务结果不会保存在RDB;
AOF 模式,可以使用 redis-check-aof 工具检查 AOF 日志文件,把未完成的事务操作从 AOF 文件中去除。可以保证一致性。
隔离性
EXEC 命令执行前:
隔离性需要通过 WATCH 机制保证。因为 EXEC 命令执行前,其他客户端命令可以被执行,相关变量会被修改;但可以使用 WATCH 机制监控相关变量。一旦相关变量被修改,则 EXEC 后则事务失败返回,具有隔离性。
EXEC 命令执行后:
Redis 是单线程执行,事务队列里的命令和其他客户端的命令只能二选一被顺序执行,因此具有隔离性
持久性
- 如果 redis 没有使用 RDB 或 AOF,事务的持久化是不存在的;
- RDB 模式:那么在一个事务执行后,而下一次的 RDB快照还未执行前,如果发生了实例宕机,数据丢失,这种情况下,事务修改的数据也是不能保证持久化;
- AOF 模式:因为 AOF 模式的三种配置选项 no、everysec 和 always
都会存在数据丢失的情况。所以,事务的持久性属性也还是得不到保证。
总结
1. Redis 的事务机制可以保证一致性和隔离性;
2. 但是无法保证持久性;
3. 具备了一定的原子性,但不支持回滚。