【redis原理】redis事务源码分析

一、前言

上一篇文章总结了redis事务的使用,今天分享redis的原理;

二、概念

redis支持事务机制,但是redis的事务机制与传统关系型数据库的事务机制并不相同。

redis事务的本质是一组命令的集合(命令队列)。事务可以一次执行多个命令,并提供以下保证
1)事务中的所有命令都按顺序执行。事务命令执行过程中,其他客户端提交的命令请求需要等待当前事务所有命令执行完成后再处理,不会插入当前事务命令队列中;
2)事务中的命令要么都执行,要么都不执行,即使事务中有些命令执行失败,后续命令依然被执行。因此redis事务也是原子的。

注意:redis不支持回滚,如果事务中有命令执行失败了,那么redis会继续执行后续命令而不是回滚。

三、redis事务命令

watch命令可以监听指定键,当后续事务执行前发现这些键已修复时,则拒绝执行事务;
multi命令可以开启一个事务,后续的命令都会被放入事务命令队列;
exec命令可以执行事务命令队列中的所有命令
discard命令可以抛弃事务命令队列中的命令,和exec命令都会结束当前事务;

四、执行示例

1)在事务执行过程中,没有其它客户端执行时

127.0.0.1:6379> set score 1
OK
127.0.0.1:6379> 
127.0.0.1:6379> 
127.0.0.1:6379> watch score
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr score
QUEUED
127.0.0.1:6379> exec
1) (integer) 2
127.0.0.1:6379> get score
"2"

可以看到exec的执行结果为:(integer)2

2)在事务执行过程中,有其它客户端修改对应key的值

在这里插入图片描述
客户端client2在客户端client1执行完incr score命令之后执行set score 10,可以看到exec执行结果为false,说明client1的事务取消执行

五、事务的实现原理

1、server.sh/multiState结构体负责存放事务信息:

typedef struct multiState {
   
   
    multiCmd *commands;     /* Array of MULTI commands */
    int count;              /* Total number of MULTI commands */
    int cmd_flags;          /* The accumulated command flags OR-ed together.
                               So if at least a command has a given flag, it
                               will be set in this field. */
    int cmd_inv_flags;      /* Same as cmd_flags, OR-ing the ~flags. so that it
                               is possible to know if all the commands have a
                               certain flag. */
    int minreplicas;        /* MINREPLICAS for synchronous replication */
    time_t minreplicas_timeout; /* MINREPLICAS timeout as unixtime. */
} multiState;

commands:事务命令队列,存放当前事务所有的命令。
客户端属性client.mstate指向一个multiState变量,该multiState作为客户端的事务上下文,负责存放该客户端当前的事务信息。

2、watch命令

redisDb中定义了字典属性watched_keys,该字典的键是数据库中被监视的redis键,字典的值是监视字典键的所有客户端列表;
watchCommand函数负责处理watch命令,该函数会调用watchForKey函数处理相关逻辑:

/* ===================== WATCH (CAS alike for MULTI/EXEC) ===================
 *
 * The implementation uses a per-DB hash table mapping keys to list of clients
 * WATCHing those keys, so that given a key that is going to be modified
 * we can mark all the associated clients as dirty.
 *
 * Also every client contains a list of WATCHed keys so that's possible to
 * un-watch such keys when the client is freed or when UNWATCH is called. */

/* In the client->watched_keys list we need to use watchedKey structures
 * as in order to identify a key in Redis we need both the key name and the
 * DB */
typedef struct watchedKey {
   
   
    robj *key;
    redisDb *db;
} watchedKey;

/* Watch for the specified key */
void watchForKey(client *c, robj *key) {
   
   
    list *clients = NULL;
    listIter li;
    listNode *ln;
    watchedKey *wk;

    /* Check if we are already watching for this key */
    listRewind(c->watched_keys,&li);
    while((ln = listNext(&li))) {
   
   
        wk = listNodeValue(ln);
        if (wk->db == c->db && equalStringObjects
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dylan~~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值