说说 Redis 事务( 二 )


  • [D]语法错误
127.0.0.1:6379> SET a 1OK127.0.0.1:6379> SET b 2OK127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET a 11QUEUED127.0.0.1:6379> SETS b 22(error) ERR unknown command 'SETS'127.0.0.1:6379> EXEC(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> GET a"1"127.0.0.1:6379> GET b"2"
当 Redis 开启一个事务后 , 若添加的命令中有语法错误,会导致事务提交失败 。这种情况下事务队列中的命令都不会被执行 。如上面例子中 a 和 b 的值都是原有的值 。这类在 EXEC 之前产生的错误,如命令名称错误,命令参数错误等,会在 EXEC 执行之前被检测出来,所以在发生这些错误的时候,事务会被取消 , 事务中的所有命令都不会执行 。(这种情况看起来是不是有点像回滚了)
  • [E]运行时错误
127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET a 1QUEUED127.0.0.1:6379> SET b helloQUEUED127.0.0.1:6379> INCR bQUEUED127.0.0.1:6379> EXEC1) OK2) OK3) (error) ERR value is not an integer or out of range127.0.0.1:6379> GET a"1"127.0.0.1:6379> GET b"hello"当 Redis 开启一个事务后,添加的命令没有出现前面说的语法错误,但是在运行时检测到了类型错误,导致事务最提交失败(说未完全成功可能更准确点) 。此时事务并不会回滚,而是跳过错误命令继续执行 。如上面的例子,未报错的命令值已经修改,a 被设置成了 1,b 被设置为了 hello,但是报错的值未被修改,即 INCR b 类型错误,并未执行,b 的值也没有被再更新 。
Redis 事务与 ACID通过上面的例子,我们已经知道 Redis 的事务和我们通常接触的 MySQL 等关系数据库的事务还有有一定差异的 。它不保证原子性 。同时 Redis 事务也没有事务隔离级别的概念 。下面我们来具体看下 Redis 在 ACID 四个特性中 , 那些是满足的,那些是不满足的 。事务执行可以分为命令入队(EXEC 执行前)和命令实际执行(EXEC 执行之后)两个阶段 。下面我们在分析的时候,很多时候都会分这两种情况来分析 。
  • 原子性(A)
上面的实例分析中,[A] , [B],[C]三种正常的情况,我们可以很明显的看出 , 是保证了原子性的 。但是一些异常情况下,是不满足原子性的 。
  1. 如 [D] 所示的情况,客户端发送的命令有语法错误,在命令入队列时 Redis 就判断出来了 。等到执行 EXEC 命令时,Redis 就会拒绝执行所有提交的命令 , 返回事务失败的结果 。此种情况下,事务中的所有命令都不会被执行了,是保证了原子性的 。
  2. 如 [E] 所示的情况 , 事务操作入队时,命令和操作类型不匹配,此时 Redis 没有检查出错误(这类错误是运行时错误) 。等到执行 EXEC 命令后,Redis 实际执行这些命令操作时,就会报错 。需要注意的是,虽然 Redis 会对错误的命令报错不执行 , 但是其余正确的命令会依次执行完 。此种情况下,是无法保证原子性的 。
  3. 在执行事务的 EXEC 命令时,Redis 实例发生了故障 , 导致事务执行失败 。此时,如果开启了 AOF 日志,那么只会有部分事务操作被记录到 AOF 日志中 。使用redis-check-aof工具检测 AOF 日志文件,可以把未完成的事务操作从 AOF 文件中去除 。这样一来,使用 AOF 文件恢复实例后 , 事务操作不会被再执行,从而保证了原子性 。若使用的 RDB 模式,最新的 RDB 快照是在 EXEC 执行之前生成的 , 使用快照恢复之后,事务中的命令也都没有执行,从而保证了原子性 。若 Redis 没有开启持久化 , 则重启后内存中的数据全部丢失,也就谈不上原子性了 。
  • 一致性(C)
一致性指的是事务执行前后,数据符合数据库的定义和要求 。这点在 Redis 事务中是满足的,不论是发生语法错误还是运行时错误,错误的命令均不会被执行 。
  1. EXEC 执行之前 , 入队报错(实例分析中的语法错误)
事务会放弃执行,故可以保证一致性 。
  1. EXEC 执行之后,实际执行时报错(实例分析中的运行时错误)
错误的命令不会被执行 , 正确的命令被执行,一致性可以保证 。
  1. EXEC 执行时 , 实例宕机
若 Redis 没有开启持久化,实例宕机重启后,数据都没有了,数据是一致的 。若配置了 RDB 方式,RDB 快照不会在事务执行时执行 。所以,若事务执行到一半,实例发生了故障,此时上一次 RDB 快照中不会包含事务所做的修改,而下一次 RDB 快照还没有执行,实例重启后,事务修改的数据会丢失,数据是一致的 。若事务已经完成,但新一次的 RDB 快照还没有生成,那事务修改的数据也会丢失 , 数据也是一致的 。若配置了 AOF 方式 。当事务操作还没被记录到 AOF 日志时,实例就发生故障了,使用 AOF 日志恢复后数据是一致的 。若事务中的只有部分操作被记录到 AOF 日志 , 可以使用

推荐阅读