泰州营销型网站建设,第一次打开wordpress白,python做网站感觉好费劲,做网站需要哪些人我们都知道redis追求的是简单#xff0c;快速#xff0c;高效#xff0c;在这种情况下也就拒绝了支持window平台#xff0c;学sqlserver的时候#xff0c;我们知道事务还算是个比较复杂的东西#xff0c;所以这吊毛要是照搬到redis中去#xff0c;理所当然redis就不是那…我们都知道redis追求的是简单快速高效在这种情况下也就拒绝了支持window平台学sqlserver的时候我们知道事务还算是个比较复杂的东西所以这吊毛要是照搬到redis中去理所当然redis就不是那么简单纯碎的东西了但是呢事务是我们写程序无法逃避的场景所以redis作者折衷的写了个简化版的事务机制下面我来扯一下它的蛋蛋。一 事务实战具体到事务是什么要保证什么。。。这个我想没必要说了先不管三七二十一看一下redis手册领略下它的魔力。1. multiexec还记得sqlserver是怎么玩的吗一般都是这样的三个步骤生成事务产生命令执行事务对吧而对应redis呢multi就是生成事务然后输入redis命令最后用exec执行命令就像下面这样可以看到我set完命令之后反馈信息是QUEUED最后我再执行exec这些命令才会真正的执行就是这么的简单一切执行的就是那么的顺利一点都不拖泥带水牛逼的不要不要的可能有些人说其实事务中还有一个rollback操作但好像在redis中没有看到哈哈牛逼哈很遗憾是redis中没有rollback操作比如下面这样。在图中我故意用lpush命令去执行string可想而知自然不会执行成功但从结果中你看到什么了呢两个OK一个Error这就是违反了事务的原子性对吧但是我该怎么反驳呢 我会说错你妹啊。。。连个基本的命令都写错了你搞个毛啊。。。还写个吊毛代码reids仅仅是个数据结构服务器多简单的一件事情退一万步说很明显的错误命令它会直接返回的比如我故意把lpush写成lpush12. watch不知道你看完multi后面的三条set命令之后有没有一种心虚的感觉怎么说呢就是只要命令是正确的redis保证会一并执行誓死完成任务虽然说命令是一起执行的但是谁可以保证我在执行命令的过程中其他client不会修改这些值呢如果修改了这些值那我的exec还有什么意义呢没关系这种烂大街的需求redis怎可能袖手旁观这里的watch就可以助你一臂之力。WATCHWATCH key [key ...]监视一个(或多个) key 如果在事务执行之前这个(或这些) key 被其他命令所改动那么事务将被打断。上面就是redis手册中关于watch的解释使用起来貌似很简单就是我在multi之前用watch去监视我要修改的key如果说我在exec之前multi之后的这段时间key被其他client修改那么exec就会执行失败返回(nil)就这么简单我还是来举个例子二原理探索关于事务操作的源代码大多都在redis源码中的multi.c 文件中接下来我会一个一个的简单剖析一下1. multi在redis的源代码中它大概是这么写的1 void multiCommand(redisClient *c) {2 if (c-flags REDIS_MULTI) {3 addReplyError(c,MULTI calls can not be nested);4 return;5 }6 c-flags | REDIS_MULTI;7 addReply(c,shared.ok);8 }从这段代码中你可以看到multi只是简单的把redisClient的REDIS_MULTI状态打开告诉这个redis客户端已经进入事务模式了对吧。2. 生成命令在redisClient中里面有一个multiState命令typedef struct redisClient {。。。multiState mstate; /* MULTI/EXEC state */。。。} redisClient;从注释中你大概也看到了这个命令和multi/exec肯定有关系接下来我很好奇的看看multiState的定义typedef struct multiState {multiCmd *commands; /* Array of MULTI commands */int count; /* Total number of MULTI commands */int minreplicas; /* MINREPLICAS for synchronous replication */time_t minreplicas_timeout; /* MINREPLICAS timeout as unixtime. */} multiState;从multiState这个枚举中你可以看到下面有一个*command命令从注释中可以看到它其实指向的是一个数组这个数组我想你闭着眼睛都能想得到吧。。。它就是你的若干条命令啦。。。下面还有一个count可以看到是实际的commands的总数。3. watch为了方便说到后面的exec这里想说一下watch大概是怎么实现的在multi.c源代码中是这样写的。1 typedef struct watchedKey {2 robj *key;3 redisDb *db;4 } watchedKey;56 void watchCommand(redisClient *c) {7 int j;89 if (c-flags REDIS_MULTI) {10 addReplyError(c,WATCH inside MULTI is not allowed);11 return;12 }13 for (j 1; j argc; j)14 watchForKey(c,c-argv[j]);15 addReply(c,shared.ok);16 }1718 /* Watch for the specified key */19 void watchForKey(redisClient *c, robj *key) {20 list *clients NULL;21 listIter li;22 listNode *ln;23 watchedKey *wk;2425 /* Check if we are already watching for this key */26 listRewind(c-watched_keys,li);27 while((ln listNext(li))) {28 wk listNodeValue(ln);29 if (wk-db c-db equalStringObjects(key,wk-key))30 return; /* Key already watched */31 }32 /* This key is not already watched in this DB. Lets add it */33 clients dictFetchValue(c-db-watched_keys,key);34 if (!clients) {35 clients listCreate();36 dictAdd(c-db-watched_keys,key,clients);37 incrRefCount(key);38 }39 listAddNodeTail(clients,c);40 /* Add the new key to the list of keys watched by this client */41 wk zmalloc(sizeof(*wk));42 wk-key key;43 wk-db c-db;44 incrRefCount(key);45 listAddNodeTail(c-watched_keys,wk);46 }这段代码中大概最核心的一点就是/* This key is not already watched in this DB. Lets add it */clients dictFetchValue(c-db-watched_keys,key);就是通过dicFetchValue这个字典方法从watched_keys中找到指定key的value而这个value是一个clients的链表说明人家其实是想找到关于这个key的所有client对吧最后还会将本次key塞入到redisclient的watched_keys字典中如下代码/* Add the new key to the list of keys watched by this client */wk zmalloc(sizeof(*wk));wk-key key;wk-db c-db;incrRefCount(key);listAddNodeTail(c-watched_keys,wk);如果非要画图大概就是这样其中watched_key是个字典结构字典的键为上面的key1key2。。。value为client的链表这样的话我就非常清楚某个key中是被哪些client监视着的对吧。4.exec这个命令里面大概做了两件事情1: 判断c-flagsREDIS_DIRTY_EXEC 打开与否如果是的话取消事务discardTransaction(c)也就是说这个key已经被别的client修改了。2: 如果没有修改那么就for循环执行comannd[]中的命令如下图中的两处信息好了大概就这么说了希望对你有帮助哈~~~