Redis 事务
Redis 事务
Redis通过 MULTI/EXEC/WATCH
等命令实现事务的功能,事务提供了一种将多个命令请求打包,一次性按顺序地执行多个命令的机制。
1 事务的实现
事务以一个 MULTI
命令开始,接着将多个命令放入事务当中,最后有 EXEC
命令将这个事务提交给服务器。
1.1 事务开始
MULTI
命令的执行标志事务的开始,将客户端从非事务状态切换为事务状态,通过客户端状态的 flags
属性实现。
1.2 命令入队
当客户端处于非事务状态,发送的命令会立即被服务器执行。
当客户端处理事务状态时,服务器会根据客户端发来的不同命令执行不同操作。
- 如果是
EXEC/DISCARD/WATCH/MULTI
命令中的一个,就会被立即执行。 - 其他命令会被放入一个事务队列里面,然后向客户端返回
QUEUED
回复。
事务队列
服务器的每个redis客户端保存自己的事务状态,事务状态包含一个事务队列和一个已入队命令的计数器,事务队列的长度。
1.3 事务执行
当一个处于事务状态的客户端向服务器发送 EXEC
命令时,这个 EXEC
命令会立即被服务器执行,服务器会遍历这个客户端的事务队列,执行所有命令并返回给客户端。
2 WATCH
WATCH
是一个乐观锁,可以在执行 EXEC
命令前监视任意数量的数据库键,并在 EXEC
命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器将拒绝执行事务,并向客户端返回事务执行失败的空恢复。
每个 Redis
数据库保存着一个 watched_keys
字典,这个字典的键是某个被 WATCH
命令监视的数据库键,而字典的值是一个链表,链表中记录了所有监视键的客户端。

2.1 监视机制的触发
当执行修改的命令时,会对 watched_keys
进行检查,如果存在,则修改对应reids客户端的 REDIS_DIRTY_CAS
标识,标识客户端的事务安全性已经被破坏。
2.3 EXEC 命令
当服务器收到 EXEC
命令时,会检测这个客户端是否打开了 REDIS_DIRTY_CAS
标识,来决定是否执行事务。

3 事务的 ACID
Redis 中,事务总是具有原子性、一致性、隔离性,对于隔离性需要在特定的持久化模式下才会有。
3.1 原子性
对于 Redis 的事务,多个操作要么全部执行,要不全不执行,满足原子性的。在的过程中,如果发生错误,那么这条事务中的所有命令都不会执行。
但是 Redis 的事务是不支持回滚的,在事务执行期间,如果某条命令运行错误,也会继续执行下去。
3.2 一致性
数据库在执行事务前后是一致的,无论事务是否执行成功,都应该保持一致。
一致性是指 数据符合数据库本身的定义和要求,没有非法、无效、错误的数据。
3.3 隔离性
多个事务并发地执行,各个事务之间不会相互影响,因为Redis使用单线程的方式来执行事务,并且保证执行过程中不会对事务进行终端,因此redis的事务总是以串行的方式运行的。
3.4 持久性
当一个事务执行完毕时,执行这个事务所得到的结果已经被保存到磁盘里面了,即使服务器宕机,也不会丢失结果。
Redis 的事务持久性由持久化模式决定:
- 无持久化的内存模式下运作时,一但停机就会丢失所有数据,事务不具有持久性。
RDB
持久化模式,只有在特定的情况下才会执行bgsave
命令,不能保证一定会被保存到硬盘里面, 事务不具有持久性。AOF
持久化模式,并且appendfsync=always
时,程序会在执行命令之后调用同步函数,将命令保存到硬盘里面,事务具有持久性。AOF
持久化模式,并且appendfsync=everysec
时,当停机时,可能会丢失一秒内的数据,事务不具有持久性。AOF
持久化模式,并且appendfsync=no
时,由操作系统来决定何时将命令同步到磁盘,当停机时,可能会丢失部分数据,事务不具有持久性。