19 事务
通过MULTI(开始事务)、EXEC(事务提交)、WATCH等命令来实现事务功能,可以将多个命令请求打包,一次性、按顺序执行,且不断被中断
例子:
19.1 事务的实现
一个事务从开始到结束会经历三个阶段:
1.事务开始
2.命令入队
3.事务执行
19.1.1 第一阶段:事务开始
MULTI命令标志着事务的开始,将客户端从非事务状态切换为事务状态,通过在客户端状态(redisClient)的flags属性中打开REDIS_MULTI标识来完成的
19.1.2 第二阶段:命令入队
客户端处于事务状态时,命令不会被服务器立即执行,会根据发送的不同命令执行不同的操作:
19.1.3 事务队列
每个客户端都有自己的事务状态multiState,保存在redisClient的mstate属性里面:
事务状态multiState包含一个事务队列multiCmd,以及事务队列的长度属性:
事务队列是一个multiCmd类型的数组,每个multiCmd元素都保存了一个已入队命令的相关信息:
事务队列以先进先出的方式处理入队的命令
例子:
19.1.4 第三阶段:事务执行
流程:
伪代码:遍历事务队列,执行所有命令;清空事务状态;封装事务执行结果返回给客户端
19.2 WATCH命令及其实现
含义及其作用:
例子:
19.2.1 使用WATCH命令监视数据库键的原理
每个Redis数据库redisDb都保存着一个watched_keys字典,键是某个被WATCH命令监视的数据库键,值是一个链表,记录了所有监视相应数据库键的客户端:
例子:对c1执行WATCH “name”,则c1被添加到字典里面,依次可得c2、c3、c4
19.2.2 监视机制的触发
时机和实现函数:
touchWatchKey伪代码:
19.2.3 判断事务是否安全
服务器接收到一个客户端发来的EXEC命令时,服务器会根据这个客户端是否打开了REDIS_DIRTY_CAS标识来决定是否执行事务:如果打开了,说明至少有一个键已经被修改过了,则不执行;如果没打开,则执行
19.2.4 一个完整的WATCH事务执行过程
一个带有WATCH的事务从开始到失败的完整过程:
1.当前字典如下:
2.客户端c10086执行WATCH “name”,字典更新如下:
3.客户端c10086执行MULTI、SET ”name“ ”peter“;客户端c999执行SET “name” ”john“
4.c10086发送EXEC,失败:
19.3 事务的ACID性质
Redis事务具有ACI,即原子性、一致性、隔离性;当运行在某种特定的持久化模式下时,具有D,持久性
19.3.1 原子性
含义:
Redis事务和关系型数据库事务的最大区别:Redis不支持事务回滚机制,即使某个命令出错,整个事务也会继续执行下去,直到命令执行完毕
不支持事务回滚机制的原因:
19.3.2 一致性
含义:
Redis通过谨慎的错误检测和简单的设计来保证事务的一致性
接下来介绍三个典型错误及其解决方案
19.3.2.1 入队错误
含义及其解决方案:
19.3.2.2 执行错误
含义:
事务在执行过程中发生错误,如对数据库键执行了错误类型的操作
说明:
解决方案:
出错的命令会被服务器识别出来,并进行相应的错误处理;而正确命令仍然执行,不会拒绝整个事务
19.3.2.3 服务器停机
含义及其解决方案:
19.3.3 隔离性
含义:
拥有隔离性的原因:
19.3.4 持久性
含义:
持久性由Redis所使用的持久化模式决定:
注意:无论什么模式,在一个事务的EXEC前加上SAVE命令总可以保证此事务的持久性