Redis事务命令与原理
本篇博客是对《Redis设计与实现》相关内容的学习和总结
日期:2020-12-14
Redis版本:3.0.6
事务相关命令
- 开始事务
multi
在执行 multi 命令后,后面执行的非事务相关的命令都会被加入事务队列,等待事务执行
- 执行事务
exec
执行 multi 和 exec 之间的命令,并统一返回
- 监视键
watch key [key ...]
监视一个或多个键,如果监视的键的值发生了改变,那么事务将不被执行,并且返回 nil。watch 命令必须在 multi 命令之前执行。
- 取消事务
discard
取消事务,清空事务队列
实现原理
-
multi 命令
当Redis接收到multi
命令时,就会将该客户端标记为事务状态。Redis服务器可以和多个客户端连接,每个客户端都有一个对应的客户端状态结构来保存这个客户端的信息,包括事务状态,套接字描述符,输入输出缓冲区还有事务队列等。当进入事务状态后,这个客户端发过来的非事务的命令都会加入到事务队列等待事务执行,而事务相关的命令则会立即执行。 -
exec 命令
当接收到exec
命令时,就会执行事务队列中的所有命令,因为Redis单线程执行命令,所以自然的执行这些命令时,不会穿插其他客户端的命令。执行完这些命令后,将返回所有命令的执行结果,并且清空事务队列,清空客户端对键的监视,退出事务状态。 -
discard 命令
当接收到discard
命令时,直接清空事务队列,清空客户端对键的监视,退出事务状态。 -
watch 命令
Redis用字典(Redis的字典用哈希表实现,基本可以将字典看作哈希表)来存储监视的键和客户端之间的关系,其中字典的键就是被监视的键名,字典的值是一个链表,每一个节点存有客户端状态结构的指针。如下图所示:

图一
client-1监视了键 "aaa" 和 "ccc",也就是执行了命令watch aaa ccc
,client-2监视了键" bbb",也就是执行了命令 watch bbb
,client-3监视了键 "ccc",也就是执行了命令 watch ccc
。当一个客户端执行watch
命令时,就会将这个客户端的状态结构指针添加到被监视的键所对应的链表的末尾。
如果有客户端对被监视的键执行了修改命令,比如对字符串类型执行了set
命令,对列表类型执行了lpush
命令等。那么就会找到监视这个键的客户端列表,对他们做标记(这个标记就在客户端状态结构中),他们监视的键被修改了。然后等到执行exec
时会做检查,如果有这个标记就不执行事务直接返回 nil。
当执行了exec
或者discard
命令时,就会清空客户端对键的监视(清空就是清除对所有键的监视),也就是将客户端状态结构指针从上图的链表中移除,执行unwatch
也可以完成同样的任务。
Redis事务的特性
- 在执行事务包含的命令时不会穿插其他客户端的命令
- 在执行命令出错时,会继续执行后续命令,没有回滚功能
参考资料
- 《Redis设计与实现》
- Redis中文文档