redis 事务
Redis 通过 MULTI 、 DISCARD 、 EXEC 和 WATCH 四个命令来实现事务功能, 本章首先讨论使用 MULTI 、 DISCARD 和 EXEC 三个命令实现的一般事务, 然后再来讨论带有 WATCH 的事务的实现。
redis的事务和mysql的事务不同:
事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制, 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后, 才会继续处理其他客户端的其他命令。
会经历3个阶段:
- 开始事务。
- 命令入队。
执行事务。
开始事务
执行事务
事务状态下的 DISCARD 、 MULTI 和 WATCH 命令
除了 EXEC 之外, 服务器在客户端处于事务状态时, 不加入到事务队列而直接执行的另外三个命令是 DISCARD 、 MULTI 和 WATCH。
DISCARD 命令用于取消一个事务, 它清空客户端的整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串 OK 给客户端, 说明事务已被取消。
Redis 的事务是不可嵌套的, 当客户端已经处于事务状态, 而客户端又再向服务器发送 MULTI 时, 服务器只是简单地向客户端发送一个错误, 然后继续等待其他命令的入队。 MULTI 命令的发送不会造成整个事务失败, 也不会修改事务队列中已有的数据。
WATCH 只能在客户端进入事务状态之前执行, 在事务状态下发送 WATCH 命令会引发一个错误, 但它不会造成整个事务失败, 也不会修改事务队列中已有的数据(和前面处理 MULTI 的情况一样)。
带 WATCH 的事务
WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。
相当于乐观锁
事务的 ACID 性质
Redis 事务保证了其中的一致性(C)和隔离性(I),但并不保证原子性(A)和持久性。
- 原子性 单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制。只有在事务队列中所有的命令执行成功,才算成功。
- 如果 Redis 服务器进程在执行事务的过程中被停止 —— 比如接到 KILL 信号、宿主机器停机,等等,那么事务执行失败。
- 当事务失败时,Redis 也不会进行任何的重试或者回滚动作。
- 一致性 Redis 的一致性问题可以分为三部分来讨论:入队错误、执行错误、Redis 进程被终结。
- 隔离性 Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。
- 持久性 因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由 Redis 所使用的持久化模式决定。根据redis存储的特性来做判断。
- 内存模式 GG 掉电就挂了
- RDB 模式 可能在事务执行之后、RDB 文件更新之前的这段时间失败 GG
- 在AOF 最为严格的 总是 SYNC 下。 每条命令在执行成功之后,都会立即调用 fsync 或 fdatasync 将事务数据写入到 AOF 文件。但是,这种保存是由后台线程进行的,主线程不会阻塞直到保存成功,所以从命令执行成功到数据保存到硬盘之间,还是有一段非常小的间隔,所以这种模式下的事务也是不持久的。
小结
- 事务提供了一种将多个命令打包,然后一次性、有序地执行的机制。
- 事务在执行过程中不会被中断,所有事务命令执行完之后,事务才能结束。
- 多个命令会被入队到事务队列中,然后按先进先出(FIFO)的顺序执行。
- 带 WATCH 命令的事务会将客户端和被监视的键在数据库的 watched_keys 字典中进行关联,当键被修改时,程序会将所有监视被修改键的客户端的 REDIS_DIRTY_CAS 选项打开。
- 只有在客户端的 REDIS_DIRTY_CAS 选项未被打开时,才能执行事务,否则事务直接返回失败。
- Redis 的事务保证了 ACID 中的一致性(C)和隔离性(I),但并不保证原子性(A)和持久性(D)
参考:redis事务