需要明确最重要一点就是,Redis的事务不保证原子性,事务出错不回滚
数据库的事务定义特点是“一系列程序执行单元,要么完全地执行,要么完全地不执行”
但是在Redis中的事务机制在某些地方跟数据库还是存在明显的不同
Github issues:https://github.com/littlejoyo/Blog/issues/
1.Redis事务机制
Redis事务会将所有命令放入一个命令队列中,再由队列中执行命令。
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
批量操作在发送 EXEC 命令前被放入队列缓存。
收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:
- 开始事务。
- 命令入队。
- 执行事务。
2. Redis事务实例
先以
MULTI
开始一个事务然后将多个命令入队到事务中
最后由
EXEC
命令触发事务, 一并执行事务中的所有命令
1 |
|
3.Redis事务的注意点
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制
所以 Redis 事务的执行并不是原子性的
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
4.讨论Redis事务的ACID
Redis 的事务保证了 ACID 中的一致性(C)和隔离性(I),但并不保证原子性(A)和持久性(D)。
原子性(一个事务所有操作要么全部成功,要么全部失败)
- redis的单个命令是原子性的
- 但是事务中的的redis命令,就算后面的命令失败/终止了(比如KILL进程,主机宕机等),此时事务失败,前面执行的命令也不会回滚。
一致性
(1)不正确入队命令的事务不会被执行,不会影响数据库的一致性
(2)命令执行中的错误,将错误包含在事务结果中,不会中断事务,不影响已执行结果,也不影响后面命令的执行,对事务的一致性也没有影响。
(3)进程终结
内存模式:如果 Redis 没有采取任何持久化机制,那么重启之后的数据库总是空白的,所以数据总是一致的。
RDB 模式:在执行事务时,Redis 不会中断事务去执行保存 RDB 的工作,只有在事务执行之后,保存 RDB 的工作才有可能开始。所以当 RDB 模式下的 Redis 服务器进程在事务中途被杀死时,事务内执行的命令,不管成功了多少,都不会被保存到 RDB 文件里。恢复数据库需要使用现有的 RDB 文件,而这个 RDB 文件的数据保存的是最近一次的数据库快照(snapshot),所以它的数据可能不是最新的,但只要 RDB 文件本身没有因为其他问题而出错,那么还原后的数据库就是一致的。
AOF 模式:因为保存 AOF 文件的工作在后台线程进行,所以即使是在事务执行的中途,保存 AOF 文件的工作也可以继续进行,因此,根据事务语句是否被写入并保存到 AOF 文件,有以下两种情况发生:
1)如果事务语句未写入到 AOF 文件,或 AOF 未被 SYNC 调用保存到磁盘,那么当进程被杀死之后,Redis 可以根据最近一次成功保存到磁盘的 AOF 文件来还原数据库,只要 AOF 文件本身没有因为其他问题而出错,那么还原后的数据库总是一致的,但其中的数据不一定是最新的。
2)如果事务的部分语句被写入到 AOF 文件,并且 AOF 文件被成功保存,那么不完整的事务执行信息就会遗留在 AOF 文件里,当重启 Redis 时,程序会检测到 AOF 文件并不完整,Redis 会退出,并报告错误。需要使用 redis-check-aof 工具将部分成功的事务命令移除之后,才能再次启动服务器。还原之后的数据总是一致的,而且数据也是最新的(直到事务执行之前为止)。
隔离性
- Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。
- 因此,Redis 的事务是总是带有隔离性的。
持久性
由redis的持久化模式决定:
内存模式-无持久化
RDB模式:服务器可能在事务执行之后、RDB 文件更新之前的这段时间失败,所以 RDB 模式下的 Redis 事务也是不持久的。
AOF模式:后台每秒fsync策略,不是主线程阻塞执行,如果在保存时宕机,可能有一秒数据丢失,也非持久的。
微信公众号
扫一扫关注Joyo说公众号,共同学习和研究开发技术。