We all know that redis is the pursuit of simple, fast, efficient, in this case also refused to support the window platform, sqlserver school time, we know that the transaction is a complicated thing, so if this copy to redis in redis, behoove is not as simple as pure things, but the transaction is, we write a program cannot escape the scene, so redis author eclectic wrote a simplified version of the transaction mechanism.

一:真正的战斗

具体是什么交易什么保证。我不认为这是必要的,先不管37二十一,看看使用手册和欣赏它的魔力。


1。多、高层

记得SQLServer玩过吗一般来说,这是三步,产生交易,产生的命令,执行交易,是正确的,和对应的使用多是生成一个交易,然后进入Redis命令,然后执行命令的执行,如以下:


你看,我完成了设置命令后,反馈信息是排队,最后我会执行exec,这些命令将真的实现了,就是这么简单,一切都是那么的顺利,一点也不慢,有些人可能会说,事实上,交易有一个回滚操作,但它似乎redis没有看到,不幸的是,在redis没有回滚操作,如以下。


在图片中,我故意用lpush要执行的命令字符串,可想而知,自然不会执行成功,但从结果看,你看到了什么两个好,一个错误,这是违反了事务的原子性,但我应该如何反驳Reids是一个数据结构服务器。这是件简单的事。在一万步中,很明显,错误的指令会回来直接,例如,我特意写lpush为lpush1。


2。看

之后不知道三集命令你看到背后的多,没有人感到内疚,怎么说,只要顺序正确,Redis的实施将确保完成任务,虽然命令进行的,但谁能保证我在命令的执行过程中,其他客户不修改这些值吗如果这些值被修改,我的执行官还意味着什么没关系,这个烂大街的需求,如何使用袖手旁观吗这里的表可以帮助你。



观察键{键}



监视一个(或多个)键,如果在执行事务之前由其他命令更改该键,则该事务将被中断。

手表的解释是上面的使用手册,它看起来很简单,我只是在多,看我修改的表的关键,如果我之前说的执行,经过这段时间的多,关键的其他客户端的修改,然后执行将失败,返回(无),我是如此简单,例如:


二:原理探索

对于该交易操作的源代码,主要是多。C文件中使用的源代码,然后我会做一个简单的分析。

1。多种

在Redis的源代码,这可能是写的。




无效multicommand(redisclient×C){
如果(C—>旗redis_multi){
AddReplyError(C,多称不能嵌套);
返回;
}
C - >旗redis_multi | =;
addreply(C,共享吧);


从这段代码中,你可以看到多只打开redisclient的redis_multi状态,并告诉redis客户端已进入交易模式。

2。生成命令

在redisclient,它有一个多态的命令:


redisclient { typedef struct



多状态MSTATE多/执行状态; / * * /



redisclient };



从注释中你也可以看到,这个命令是一定要多/执行相关的,然后我很好奇多态的定义:


typedef struct多态{

multicmd *命令阵列多命令; / * * /

int计算多个命令的总数;

国际minreplicas minreplicas同步复制; / * * /

time_t minreplicas_timeout minreplicas超时UnixTime; / * * /

多态};



从各州的枚举,你可以看到下面有一个*命令。从注释中,可以看到它指向一个数组,这是您的一些命令。

三.看

为了更容易地讨论后面的执行程序,这里有一个关于表如何可能完成的想法,它是在多C源代码中编写的。


watchedkey { typedef struct
robj *键;
redisdb *分贝;
watchedkey };

无效watchcommand(redisclient×C){
Int J;

如果(C—>旗redis_multi){
AddReplyError(C,看里面多是不允许的);
返回;
}
为(J = 1;J argc;j++)
WatchForKey(C,C -> argv {,});
addreply(C,共享吧);
}

注意指定的键*
无效watchforkey(redisclient * C,robj *键){
列表*客户端=空;
ListIter Li;
思路:* LN;
watchedkey *周;

检查我们是否已经在看这个键了。
ListRewind(C→watched_keys,李);
而(((Ln = listnext(李))){
周= listnodevalue(LN);
如果(WK ->分贝= = C - > DB equalstrinbjects(关键,WK—>键))
已监视返回密钥;
}
此密钥在这个数据库中还没有被监视。让我们加上它。
客户= dictfetchvalue(C ->数据库-> watched_keys,关键);
如果(!客户){
客户= listcreate();
DictAdd(C ->数据库-> watched_keys,关键客户);
incrrefcount(关键);
}
listaddnodetail(客户,C);
将新密钥添加到该客户端监视的密钥列表中。
周= zmalloc(sizeof(*周));
键=键;
周> db = C = db;
incrrefcount(关键);
ListAddNodeTail(C→watched_keys,周);
}


这个代码中最重要的一点是:


此密钥在这个数据库中还没有被监视。让我们加上它。

客户= dictfetchvalue(C ->数据库-> watched_keys,关键);



这本字典是通过dicfetchvalue方法,从watched_keys找到指定的核心价值,而价值是客户的名单,这表明人们实际上要重点发现所有的客户端,最后将钥匙插入redisclient watched_keys词典中,下面的代码:


将新密钥添加到该客户端监视的密钥列表中。

周= zmalloc(sizeof(*周));

键=键;

周> db = C = db;

incrrefcount(关键);

ListAddNodeTail(C→watched_keys,周);



如果你不必画一幅画,那可能就是这样。


watched_key是字典的结构,并对字典的键key1,key2。价值是客户的名单,所以我非常了解的客户是在某个关键监测。

4.exec

这条命令有两件事要做:

判断C ->旗帜= redis_dirty_exec是否开放,如果是这样的话,取消交易discardtransaction(C),也就是说,这已经被其他用户修改关键。

如果没有进行修改,然后在comannd { }的命令是在循环执行,如下图的两个信息:
U3000 U3000

好吧,就是说,我希望能帮助你。
EndFragment