Redis 事务

本文将介绍 Redis 中的事务。

一、说明

在 Redis 中,事务的本质是一组将被连续执行的命令的集合

二、特性

  • 顺序执行:Redis 会将事务中的所有命令序列化,按顺序执行
  • 不被打断:Redis 会一次性执行事务,并不会在过程中执行其它命令
  • 无原子性:不支持原子性,可能有部分子命令执行成功,部分子命令执行失败

三、三个阶段

分别为:

  • 开启事务
  • 命令入队
  • 执行事务或取消事务
1
2
3
4
5
6
7
8
9
10
11
// 开启事务
MULTI

// 命令入队
···

// 执行事务
EXEC

// 取消事务
DISCARD

四、对事务特性的支持

1. 原子性

(1) 对原子性的支持

  • 如果某个命令本身有语法错误,Redis 会在 “命令入队” 时报错,并在 “执行事务” 时报错并拒绝执行所有命令 ,能保证原子性

  • 如果某个命令执行错误,Redis 不会回滚之前的命令,并且还会继续执行之后的命令,无法保证原子性

    与 MySQL 不同,Redis 不支持事务回滚,这是因为 Redis 是一款基于内存的简单存储系统,如果支持回滚机制,会让其变得冗余

  • 如果事务执行过程中,Redis 发生故障,

    • 若 Redis 开启 AOF 日志,部分已经执行的命令将会被记录到日志中,可以通过 redis-check-aof 工具将未完整的事务操作从日志中去除,以保证原子性
    • 若 Redis 开启 RDB 快照,
      • 若事务执行到一半,事务执行时不会进行快照,因此事务将会全部失败,能保证原子性
      • 若事务执行完成,且 RDB 快照已经生成,则事务改动可以通过快照恢复,原子性能够保证
      • 若事务执行完成,但 RDB 快照还未生成,则事务改动会全部丢失

(2) Lua 脚本

Redis 支持执行 Lua 脚本,它的功能和事务非常类似。

Redis 执行 Lua 脚本时,也会将其中的命令一次性执行完成。与事务的区别在于,如果出现执行错误,则错误之后的语句不会再被执行。

需要注意的是,机制执行到一半时出了错,Redis 也不会将之前的语句回滚,只是会停止继续执行而已。

2. 一致性

无论如何执行,都不会影响数据的完整性和一致性,能够保证。

3. 隔离性

(1) “事务开启 ~ 事务执行” 过程中的隔离性保证

Redis 并没有直接提供保证,但提供了解决措施。

可以使用 WATCH 命令监视键值对,如果在事务执行之前这些键值对发生了改变,则事务将会执行失败,从而避免事务被其它命令影响,保证事务的隔离性。

相关命令:

  • WATCH key名 ···:监视键值对
  • UNWATCH:取消对所有键值对的监视
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 监视hello和hi
WATCH hello hi

// 开启事务
MULTI

// 命令入队
···

// 执行
EXEC

// 取消监视
UNWATCH

如果在执行前,hello 或 hi 对应的键值对发生了改变,则事务将会执行失败。

(2) “事务执行” 过程中的隔离性保证

Redis 能够保证事务中的命令 顺序执行不被打断

4. 持久性

因为 Redis 自身持久化方案上的缺陷,无法保证持久性。

参考