Redis事务内部机制

1:MULTI 命令的执行标记着事务的开始

2:命令入队客户端进入事务状态之后, 服务器在收到来自客户端的命令时, 不会立即执行命令, 而是将这些命令全部放进一个事务队列里, 然后返回 QUEUED , 表示命令已入队。

每个Redis客户端都有自己的事务状态,事务状态包含一个事务队列,一个已入队命令的计数器。

typedef struct multiState{

//事务队列,FIFO顺序(数组)

multiCmd *commands;

//已入队命令计数

int count;

} multiState;

事务队列是一个数组, 每个数组项是都包含三个属性:

typdef struct multiCmd{

//命令的参数

robj ** argv;

//参数数量

int argc;

// 命令指针

struct redisCommand *cmd;

} multiCmd;

3: EXEC 命令执行时, 以先进先出(FIFO)的方式遍历执行客户端事务队列中的命令。执行完后, EXEC 命令会将回复队列返回给客户端, 客户端清零入队命令计数器,释放事务队列,返回到非事务状态。

4:DISCARD 命令用于取消一个事务, 它清空客户端的整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串 OK 给客户端, 说明事务已被取消

5:WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。在事务状态下发送 WATCH 命令会引发一个错误, 但它不会造成整个事务失败, 也不会修改事务队列中已有的数据。

WATCH 命令的实现

数据库的 redis.h/redisDb 结构类型中, 都保存了一个 watched_keys 字典, 字典的键是这个数据库被监视的键, 而字典的值则是一个链表, 链表中保存了所有监视这个键的客户端。WATCH 命令的作用, 就是将当前客户端和要监视的键在 watched_keys 中进行关联

WATCH 的触发

当客户端发送 EXEC 命令、触发事务执行时, 服务器会对客户端的状态进行检查:

1::如果客户端的 REDIS_DIRTY_CAS 选项已经被打开,那么说明被客户端监视的键至少有一个已经被修改了,事务的安全性已经被破坏。服务器会放弃执行这个事务,直接向客户端返回空回复,表示事务执行失败。

2:如果 REDIS_DIRTY_CAS 选项没有被打开,那么说明所有监视键都安全,服务器正式执行事务

redis事务中需要注意的地方:

1:入队命令语法错误,此时还没有执行exec命令

虽然redis在碰到exec命令之前不会执行事务中的命令,但是,它会对每个命令进行适当的检查,当发现有某些明显的语法错误时,如参数个数不正确,则会在入队时,返回错误信息,并当看到exec命令调用discard命令进行回滚

2:当exec执行完毕后,执行其它命令时发生错误

当redis在执行命令时,如果出现了错误,那么redis不会终止其它命令的执行。即只要是正确的命令,无论在错误命令之前还是之后,都会顺利执行

3:事务间的相互影响

如果两个事务同时修改一条记录,而redis中的事务默认没有对此进行处理,首先执行exec的事务的结果将会被覆盖。这里我们可以使用watch命令,该命令用于监控某些具体的key,如果这些key被其它事务修改了,那么本事务再修改时就不会成功,然后返回失败的提示

发布了50 篇原创文章 · 获赞 2 · 访问量 2284

猜你喜欢

转载自blog.csdn.net/eafun_888/article/details/104738549
今日推荐