首页 > 代码库 > redis 事务
redis 事务
事务相关命令
Redis通过multi,discard,exec和watch四个命令来实现事务功能,
一般事务
- multi
- discard
- exec
特殊:watch
服务器在执行完事务中的所有命令之后,才会继续处理其他客户端的其他命令
事务由multi开启,将多个命令入队到事务中,最后exec命令触发事务,一并执行性:
一个事务从开始到执行会经历以下三个阶段:
- 开始事务。
- multi命令将服务器切换到事务状态
- 命令入队。
- 将命令放进事务队列里
- 执行事务。
- 从事务对列中取出命令并执行
事务队列是一个数组,每个数组项包含三个属性
- 要执行的命令(cmd)
- 命令的参数(argv)
- 参数的个数(argc)
例子:
举个例子,如果客户端执行以下命令:
redis> MULTI OK redis> SET book-name "Mastering C++ in 21 days" QUEUED redis> GET book-name QUEUED redis> SADD tag "C++" "Programming" "Mastering Series" QUEUED redis> SMEMBERS tag QUEUED
程序为客户端创建一下事务队列
exec,discard,multi,watch 是不放入事务队列中的,而是直接执行的。
事务队列的执行结果,放入回复队列中,当执行exec命令会将回复队列作为自己的执行结果放回客户端,
并从事务状态返回到非事务状态。
无论在事务状态下,还是在非事务状态下,Redis 命令都由同一个函数执行,所以它们共享很
多服务器的一般设置,比如 AOF 的配置、 RDB 的配置,以及内存限制,等等
事务中命令和普通命令的区别
- 非事务状态下的命令以单个命令为单位执行,前一个命令和后一个命令的客户端不一定是同一个;
- 而事务状态则是以一个事务为单位,执行事务队列中的所有命令:
- 除非当前事务执行完毕,否则服务器不会中断事务,也不会执行其他客户端的其他命令。
- 在非事务状态下,执行命令所得的结果会立即被返回给客户端;
- 而事务则是将所有命令的结果集合到回复队列,再作为 EXEC 命令的结果返回给客户端
Redis 的事务是不可嵌套的,处于事务状态的客户端在发送multi,则服务器只会返回一个简单错误不做任何操作,
继续等待其他命令入队。
DISCARD
- 命令用于取消一个事务,它清空客户端 的整个事务队列,然后将客户端从事务状态调回非事务状态
WATCH
- 只能在客户端进入事务状态之前执行,在事务状态下发送 WATCH 命令会引发一个简单错误,不会做其他改变
- 命令用于在事务开始之前监视任意数量的键:
- 当调用 EXEC 命令执行事务时,如果任意一个被监视的键已经被其他客户端修改了,
- 那么整个事务不再执行,直接返回失败。
- watch一个key,这个key只能是自己改动,别人不能改,如果别人改了,我就不玩儿了。
- 也就是事务的安全性
WATCH命令的实现
存储
watch_keys 字典,字典的键是这个数据库被监控的键值,而字典的值则是一个链表,链表保存所有监视这个键的客户端。
watch 触发
在任何对数据库键空间( key space)进行修改的命令成功执行之后(比如 FLUSHDB 、 SET、DEL 、LPUSH 、SADD 、ZREM ,诸如此类),
multi.c/touchWatchKey 函数都被调用,检查数据库的watch_keys字典,看是否有客户端在监视已经被命令修改的键。
如果有, 程序将所有监视这个/这些被修改键的客户端的 REDIS_DIRTY_CAS 选项打开,表明事务安全性已经被破坏。
当客户端发送exec命令,触发事务执行性,服务器会对客户端状态进行检查:
REDIS_DIRTY_CAS
- 被打开事务安全性已经被破坏,放弃事务,返回执行失败
- 否则,服务器执行所有事务
最后,当一个客户端结束它的事务时,无论事务是成功执行,还是失败,watched_keys字典中和这个客户端相关的资料都会被清除。
事务的ACID性质
在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的安全性。
Redis 事务保证了其中的一致性( C)和隔离性( I),但并不保证原子性( A)和持久性( D)
原子性(Atomicity)
事务中命令要么全部执行成功,有一条失败则全部回滚
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以Redis事务的执行并不是原子性的
如果 Redis 服务器进程在执行事务的过程中被停止,那么事务执行失败,但是不会回滚。
一致性(Consistency)
redis的一致性问题分三部分
- 入队错误
- 执行错误
- redis进程被终结
入队错误
客户端向服务器发送了错误的命令。
- 服务器将想客户端返回出错信息,并将客户端设为REDIS_DIRTY_EXEC状态。
- 当执行exec命令时,Redis拒绝执行状态为 REDIS_DIRTY_EXEC 的事务。
- 因此,带有不正确入队命令的事务不会被执行,也不会影响数据库的一致性
执行错误
对一个不同类型的 key 执行了错误的操作
- Redis 只会将错误包含在事务的结果中
- 这不会引起事务中断或整个失败
- 不会影响已执行事务命令的结果
- 也不会影响后面要执行的事务命令
- 所以它对事务的一致性也没有影响
redis进程被终结
Redis 进程被终结 那么
根据 Redis 所使用的持久化模式,可能有以下情况出现:
- 内存模式
- 如果 Redis 没有采取任何持久化机制,那么重启之后的数据库总是空白的,所以数据总是一致的。
- RDB模式
- 在执行事务时,Redis 不会中断事务去执行保存 RDB 的工作,只有在事务执行之后,保存 RDB 的工作才有可能开始。
- 所以当 RDB 模式下的 Redis 服务器进程在事务中途被杀死时,事务内执行的命令,不管成功了多少,都不会被保存到 RDB文件里。
- 恢复数据库需要使用现有的 RDB 文件,而这个 RDB 文件的数据保存的是最近一次的数据库快照( snapshot),所以它的数据可能不是最新的
- 但只要 RDB 文件本身没有因为其他问题而出错,那么还原后的数据库就是一致的。
- AOF模式
- 因为保存 AOF 文件的工作在后台线程进行,所以即使是在事务执行的中途,保存 AOF 文件的工作也可以继续进行
- 因此,根据事务语句是否被写入并保存到 AOF文件,有以下两种情况发生:
- 如果事务语句未写入到 AOF 文件,或 AOF 未被 SYNC 调用保存到磁盘
- 那么当进程被杀死之后,Redis 可以根据最近一次成功保存到磁盘的 AOF 文件来还原数据库
- 只要 AOF 文件本身没有因为其他问题而出错,那么还原后的数据库总是一致的,但其中的数据不一定是最新的
- 如果事务的部分语句被写入到 AOF 文件,并且 AOF 文件被成功保存
- 那么不完整的事务执行信息就会遗留在 AOF 文件里
- 当重启 Redis 时,程序会检测到 AOF 文件并不完整,Redis 会退出,并报告错误
- 需要使用 redis-check-aof 工具将部分成功的事务命令移除之后,才能再次启动服务器。
- 还原之后的数据总是一致的,而且数据也是最新的(直到事务执行之前为止)。
- 如果事务语句未写入到 AOF 文件,或 AOF 未被 SYNC 调用保存到磁盘
隔离性(lsolation)
Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执
行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。
持久性(Durability)
因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事
务的持久性由 Redis 所使用的持久化模式决定:
- 在单纯的内存模式下,事务肯定是不持久的。
- 在RDB模式下,服务器可能在事务执行之后,RDB文件更新之前的这段时间失败,所以RDB模式下的Redis 事务也是不持久的
- 在AOF的“总是 SYNC ”模式下,事务的每条命令在执行成功之后,都会立即调用 fsync或 fdatasync 将事务数据写入到 AOF 文件。
- 但是,这种保存是由后台线程进行的,主线程不会阻塞直到保存成功,所以从命令执行成功到数据保存到硬盘之间,还是有一段非常小的间隔,所以这种模式下的事务也是不持久的
- 其他 AOF 模式也和“总是 SYNC ”模式类似,所以它们都是不持久的
小结
- 事务提供了一种将多个命令打包,然后一次性、有序地执行的机制。
- 事务在执行过程中不会被中断,所有事务命令执行完之后,事务才能结束。
- 多个命令会被入队到事务队列中,然后按先进先出( FIFO)的顺序执行。
- 带 WATCH 命令的事务会将客户端和被监视的键在数据库的 watched_keys 字典中进行关联,
- 当键被修改时,程序会将所有监视被修改键的客户端的REDIS_DIRTY_CAS选项打开。
- 只有在客户端的 REDIS_DIRTY_CAS 选项未被打开时,才能执行事务,否则事务直接返回失败。
- Redis 的事务保证了 ACID 中的一致性( C)和隔离性( I),但并不保证原子性( A)和持久性( D)。
redis 事务
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。