Redis 事务

Redis 事务

八月 20, 2025 次阅读

Redis事务的概念

Redis的事务与MySQL的事务概念类似,都是将一系列操作绑定为一个整体,使其能够批量执行。但与MySQL相比,Redis事务在实现上更为简单,功能也相对弱化。

Redis事务的主要特点包括:

  • 弱化的原子性:Redis没有回滚机制,只能实现命令的批量执行,无法做到“一个失败就恢复到初始状态”。
  • 不保证一致性:Redis事务不涉及约束检查,也没有回滚机制,执行结果只保证命令能依次执行,但不保证事务中途不会出现非法状态。
  • 不需要隔离性:由于Redis是单线程处理请求的,因此不会并发执行事务,也就不存在复杂的隔离级别问题。
  • 不保证持久性:事务操作结果仅保存在内存中,是否持久化取决于Redis自身的持久化机制,与事务无关。

本质上,Redis事务是通过在服务器端维护一个“事务队列”来实现的。客户端在事务中提交的命令会先进入队列,只有在发送 EXEC 命令时,事务队列中的所有操作才会被依次执行。因此,Redis事务只能保证队列中命令的连续执行,而不像MySQL事务那样具备严格的ACID特性。

总结来说,Redis事务更像是“批量执行命令”的机制,而不是传统意义上的完整事务控制。

Redis事务的操作与机制

Redis事务通过一组命令来完成,用户可以将多个命令绑定在一起,最后一次性执行。与传统数据库不同,Redis事务更像是批量执行命令的过程,但其控制逻辑却与乐观锁机制十分相似:先提交,再判断是否允许提交,如果不允许则回退,不会执行任何操作。在事务提交的竞争中,Redis也遵循谁先提交,谁生效的原则,而不是谁先开启事务。

事务的相关指令

  1. MULTI
    用于开启一个事务。执行成功后返回 OK,此时事务进入开启状态,接下来输入的命令并不会立刻执行,而是进入事务队列中等待提交。

    127.0.0.1:6379> MULTI
    OK
  2. EXEC
    用于真正执行事务。事务队列中的所有命令会依次执行。如果在执行前,被 WATCH 监控的键发生了变化,则整个事务会被放弃,所有命令都不会执行。

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set k1 1
    QUEUED
    127.0.0.1:6379> set k2 2
    QUEUED
    127.0.0.1:6379> EXEC
    1) OK
    2) OK
  3. DISCARD
    用于放弃当前事务。执行后会清空事务队列,之前加入的操作都不会被执行。

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set k1 1
    QUEUED
    127.0.0.1:6379> DISCARD
    OK
  4. WATCH
    用于监控一个或多个 key。在事务执行前,如果被监控的 key 被修改,则事务会失败并回滚,不会执行队列中的任何命令。这就像是一种乐观锁机制,确保事务在提交时数据没有被其他客户端篡改。

    127.0.0.1:6379> WATCH key
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set key 100
    QUEUED
    # 如果此时有其他客户端修改了 key
    127.0.0.1:6379> EXEC
    (nil)   # 执行失败

Redis事务的机制

Redis事务的实现机制可以概括为以下几点:

  1. 命令入队
    当事务开启后,客户端的命令不会立即执行,而是进入事务队列,直到收到 EXEC 才会一并提交。

  2. 乐观锁机制
    在事务提交时,Redis会检查被 WATCH 监控的键是否发生过修改。如果检测到修改,整个事务都会失败并回滚。

    • Redis通过版本号机制来实现这一判断,每次 key 被修改都会更新其版本号。
    • 在提交事务时,Redis会检查事务开始时记录的版本号与当前版本号是否一致,如果不一致则说明 key 被修改过,此时事务作废。
  3. ABA问题的避免
    这种版本号机制与Java中的ABA问题处理方式类似。即便一个 key 的值被改为原来的值,版本号依然会发生变化,从而避免“值未变但实际被修改过”的情况。

  4. 提交优先级
    Redis事务并不按照开启时间来决定生效顺序,而是根据谁先提交来决定结果。这样可以最大限度提高并发处理能力。


通过以上机制,Redis事务在保证性能的同时,利用 WATCH + 版本号机制实现了类似乐观锁的控制策略,确保了事务在提交阶段的数据一致性。

Redis事务的注意事项:重启或关闭时的行为

当 Redis 在事务尚未提交时发生重启、崩溃或被关闭,未提交的事务命令会被丢弃,效果类似执行了 DISCARD:

AOF 持久化中的事务完整性保障

  • Redis 使用单次 write (2) 系统调用将事务写入 AOF,保证原子性。
  • 如果在此过程中发生崩溃,AOF 文件末尾可能残留半条事务,Redis 启动时会检测并拒绝加载文件,防止加载不完整事务。可使用 redis-check-aof 工具修复。
  • 官方指出:“Redis 重启后要么加载完整事务,要么完全忽略它,不会出现部分执行的情况。”

AOF 异常加载时的行为

  • 如果 AOF 文件末尾存在不完整命令,Redis 默认会截断它并继续加载,优先保证系统可用性。因此若在事务未提交前被截断,所有未执行的命令都会被丢弃。所以一般不需要担心 Redis 启动后会加载不完整的事务。

实战建议与注意事项

  • 尽快提交事务:开启事务后应及时使用 EXEC,避免操作滞留于队列中。
  • 使用合适的持久化策略:AOF 请配置适当 fsync 策略以减少数据丢失风险。
  • 启动故障自动修复:若启动时报 AOF 异常,可用 redis-check-aof --fix 修复。
  • 事务加载机制解释:Redis 保证“事务要么完整加载,要么完全不加载”,避免部分执行不一致。