第十九章 事务

Redis的事务是指将多个命令请求打包,一次性地,按顺序执行的机制。通过MULTI、EXEC、WATCH等命令实现事务功能。

19.1 事务的实现

  19.1.1 事务的开始

  MULTI命令的执行代表了一个事务的开始,会将执行该命令的客户端由非事务状态切换成事务状态(在客户端状态的flags属性中打开REDIS_MULTI标识)

  19.1.2 命令入队

  • 非事务状态下,一个命令会被服务器立即执行。
  • 事务状态
    • EXEC、DISCARD、WATCH、MULTI命令会被立即执行
    • 其余命令放入一个事务队列,向客户端返回QUEUED回复

  19.1.3 事务队列

  每个Redis客户端由自己的事务状态,保存在mstate属性中

typedef struct redisClient{
    //事务状态
    multiState mstate;
    //...

} 

  事务状态包含了一个事务队列(一个multiCmd类型的数组),以及入队命令的计数器

typedef struct multiState{
    //事务队列,FIFO顺序
    multiCmd *commands;
    //已入队命令计数器
    int count;
}multiState;
typedef struct multiCmd{
    //参数
    robj **argv;
    //参数数量
    int argc;
    //命令指针
    struct redisCommand *cmd;

}multiCmd;

  19.1.4 执行事务

  当处于事务状态的客户端向服务器发送EXEC命令时,服务器会将客户端状态事务队列中的所有命令顺序执行,每执行完一个命令将结果暂存,全部执行完之后,移除客户端的事务状态标识,并清空客户端的事务状态,包括入队命令计数器和释放事务队列,最后将所有结果返回给客户端

19.2 WATCH命令的实现

  WATCH命令是一个乐观锁,用于监测任意数量的数据库键,在EXEC执行时,检测被监视的键是否至少有一个已经被修改了,如果是的话,服务器将拒绝执行事务,并向客户端返回代表事务执行失败的空回复。

  19.2.1 使用WATCH命令监视数据库键

  每个Redis数据库保存了一个watched_keys字典,字典的键是被监视的数据库的键,字典的值是一个链表,保存了监视这个键的所有客户端  

typedef struct redisDb{
    //正在被WATCH命令监视的键
    dict *watched_keys;
    //...
}redisDb;

  客户端通过执行WATCH命令,将自身添加到watched_keys字典当中

  19.2.2 监视机制的触发

  所有对数据库进行键相关的操作命令,在执行完毕之后,都会检查watched_keys字典,查看相应的键是否有正在监视的客户端,有的话,会打开对应客户端的REDIS_DIRTY_CAS标识,表示该客户端的事务安全性被破坏

  19.2.3 判断事务是否安全

  当客户端发起EXEC命令时,服务器会检查当前客户端是否打开了REDIS_DIRTY_CAS标识,打开则拒绝执行事务

19.3 事务的ACID性质

  A原子性,C一致性,I隔离性,D持久性

  19.3.1 原子性

  事务队列中的命令要么都执行,要么都不执行。这中间会存在某条命令执行出错的情况,Redis的事务不支持回滚,命令执行出错依然继续执行后续的命令

  19.3.2 一致性   

  事务执行前后,数据库状态都是一致的。一致是指,数据库中没有非法或者无效的错误数据。可能存在的错误如下

  1. 入队错误:命令格式错误或者命令的执行函数不存在,会拒绝执行整个事务
  2. 执行错误:执行出错会有相应的错误处理,不会修改数据库
  3. 服务器停机:如果有持久化操作,还原之后不会存在错误数据,如果没有,空白的数据库也不存在错误数据

  19.3.3 隔离性

  多个时间的执行不会相互干扰,因为Redis使用单线程的方式执行事务,执行事务期间不会中断,即Redis中的事务均是以串行的方式执行

  19.3.4 持久性

  只有在事务执行完成之后,这次事务中的命令全部被持久化,才具备持久性。只有AOF持久化模式,并且appendfsync选项为always时,事务具有持久性

19.4 单线程处理请求的Redis为何需要事务

  单个服务器可以处理多个客户端的请求,中间的处理过程可能是交替执行的,某个客户端想要自己的命令被连续执行,则需要开启事务

  

人生就像蒲公英,看似自由,其实身不由己。
原文地址:https://www.cnblogs.com/walker993/p/14477121.html