我们都知道redis追求的是简单,快速,高效,在这种情况下也就拒绝了支持window平台,学sqlserver的时候,我们知道事务还算是个比较复杂的东西,

所以这吊毛要是照搬到redis中去,理所当然redis就不是那么简单纯碎的东西了,但是呢,事务是我们写程序无法逃避的场景,所以redis作者折衷的写了个简

化版的事务机制,下面我来扯一下它的蛋蛋。

一: 事务实战

具体到事务是什么,要保证什么。。。这个我想没必要说了,先不管三七二十一,看一下redis手册,领略下它的魔力。

1. multi,exec

还记得sqlserver是怎么玩的吗?一般都是这样的三个步骤,生成事务,产生命令,执行事务,对吧,而对应redis呢??multi就是生成事务,然后

输入redis命令,最后用exec执行命令,就像下面这样:

可以看到,我set完命令之后,反馈信息是QUEUED,最后我再执行exec,这些命令才会真正的执行,就是这么的简单,一切执行的就是那么的顺利,

一点都不拖泥带水,牛逼的不要不要的,可能有些人说,其实事务中还有一个rollback操作,但好像在redis中没有看到,哈哈,牛逼哈,很遗憾是

redis中没有rollback操作,比如下面这样。

在图中我故意用lpush命令去执行string,可想而知自然不会执行成功,但从结果中,你看到什么了呢?两个OK,一个Error,这就是违反了事务

的原子性,对吧,但是我该怎么反驳呢??? 我会说,错你妹啊。。。连个基本的命令都写错了,你搞个毛啊。。。还写个吊毛代码,reids仅仅

是个数据结构服务器,多简单的一件事情,退一万步说,很明显的错误命令它会直接返回的,比如我故意把lpush写成lpush1:

2. 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;

5

6 void watchCommand(redisClient *c) {

7     int j;

8

9     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 }

17

18 /* 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;

24

25     /* 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. Let's 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. Let's 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是个字典结构,字典的键为上面的key1,key2。。。,value为client的链表,这样的话,我就非常清楚某个key

中是被哪些client监视着的,对吧。

4.exec

这个命令里面大概做了两件事情:

<1>:   判断c->flags=REDIS_DIRTY_EXEC 打开与否,如果是的话,取消事务discardTransaction(c),也就是说这个key已经

被别的client修改了。

<2>:   如果没有修改,那么就for循环执行comannd[]中的命令,如下图中的两处信息:

好了,大概就这么说了,希望对你有帮助哈~~~

redis watch使用场景_redis不得不会的事务玩法相关推荐

  1. redis watch使用场景_redis使用watch完成秒杀抢购

    {"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...

  2. 企业员工福利积分商城系统:深耕福利场景,解锁福利采购新玩法!

    近年来,经济结构升级,福利待遇增长明显,单靠高薪已较难留住公司的优秀人才.如何为企业员工提供更具吸引力的员工福利计划,逐渐成为许多企业人力资源管理战略的重要环节. 然而,企业管理者在面对员工福利时通常 ...

  3. list redis 怎样做排行_Redis中5种数据结构的使用场景介绍

    一.redis 数据结构使用场景 原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的源码.目前目标是吃透 redis 的数据结构.我们都知道,在 ...

  4. 大容量类 Redis 存储的场景补充-pika

    2019独角兽企业重金招聘Python工程师标准>>> 导读 我们在<大容量类 Redis 存储 - 有关 pika 的一切>里介绍过pika的诞生.pika的特点.pi ...

  5. redis同步效率秒_redis过期策略、内存淘汰策略、持久化方式、主从复制

    一.Redis的过期策略以及内存淘汰策略: 1.过期策略:定期删除+惰性删除: ①定期删除:redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除.注意这里 ...

  6. python使用redis在实际场景使用_用python操作redis及redis的一些应用场景

    redis安装 网上很多windows.Linux的安装教程,可根据自己的需要寻找对应教程安装 redis-py安装 pip install redis redis可视化工具 API的使用 redis ...

  7. Redis 的应用场景

    之前讲过Redis的介绍,及使用Redis带来的优势,这章整理了一下Redis的应用场景,也是非常重要的,学不学得好,能正常落地是关键. 下面一一来分析下Redis的应用场景都有哪些. 1.缓存 缓存 ...

  8. gin redis 链接不上_Redis 高并发问题,及解决方案!

    (一)redis技术的使用: redis真的是一个很好的技术,它可以很好的在一定程度上解决网站一瞬间的并发量,例如商品抢购秒杀等活动... redis之所以能解决高并发的原因是它可以直接访问内存,而以 ...

  9. Redis概述_使用命令对redis的数据进行增删改查_Jedis连接redis进行数据操作_redis进行数据缓存案例

    学习目标 redis 概念 下载安装 命令操作 1. 数据结构 持久化操作 使用Java客户端操作redis Redis 前言(从百度上抄的, 看看了解一下, 懒得排版了) 1. 概念: redis是 ...

最新文章

  1. sql between
  2. 在MFC中使用Static text控件显示消息
  3. 有“声”以来,语音如何识别?
  4. unity中单位是米还是厘米_【一步数学】小学数学单位换算公式大全及专项训练...
  5. 人类一败涂地邀请好友一直显示连接服务器,人类一败涂地怎么邀请好友 局域网创建房间方法图文教学-游侠网...
  6. “直播带货”还能火多久?
  7. Linux工作笔记031---Centos7.3下安装tomcat
  8. Matlab中计算程序运行时间的三种方法,以及获取系统时间的方法
  9. hdu2846(字典树)
  10. linux发布成服务,linux服务简单部署
  11. 阿里云与SUSE共同畅聊云原生
  12. 【软件使用技巧】二(Word文档损坏)
  13. 凸优化第九章无约束优化 9.2下降方法
  14. 图形验证码实现(代码)
  15. NodeJS博客实战26_源码与总结
  16. github 443问题
  17. v-charts使用
  18. TypeError: Class constructor ServeCommand cannot be invoked without ‘new‘
  19. 分享多张图片到微信朋友圈
  20. Andorid-15k+的面试题。

热门文章

  1. 在 Azure Functions 上使用不同的路由前缀
  2. 高效的动态URL限流实现
  3. MediatR 在.NET应用中的实践
  4. 让前端与后端异步起来
  5. 微软发布了Visual Studio 2022 RC版,并将在11月8日发布正式版
  6. Dapr牵手.NET学习笔记:状态管理进阶(一)
  7. 一篇文章带你分清楚JWT,JWS与JWE
  8. 云原生ASP.NET Core程序的可监测性和可观察性
  9. EPPlus导出Excel感觉很不错~~~
  10. 腾讯二面挂了,就因为这个...