(2).StringGet:读取数据,可以一次性读取一个key的value,也可以一次性读取多个key对应的value的凑集。
(3).StringAppend:在原有值的根本上进行拼接追加.
(4).StringLength:获取值的长度

(5).StringIncrement:数值自增n,返回自增后的值
(6).StringDecrement:数值自减n,返回自减后的值
4.通用Api操作(1).Execute("FLUSHDB"):删除所有数据,类似SqlServer的truncate
(2).KeyDelete:根据key删除数据,可以删除单个key,也可以删除多个key
(3).KeyExists:判断key是否存在,也可以单个key或者多个key
(4).KeyRename:重命名key
(5).KeyExpire:设置对应key的的过期韶光
常用string类型Api代码:
1 //1. 最大略的key-value的添加,如果该key已存在,则实行的是附加操作 2 //可以设置过期韶光哦 3 bool a1 = db.StringSet("101", "keen"); 4 5 //2. 根据key获取值 6 string data1 = db.StringGet("101"); 7 8 //3. 在原有的value上进行追加 9 //在原有值的根本上追加,返回值是终极字符串的长度,如果没有这个key,则当做一个新的key进行添加10 long data2 = db.StringAppend("101", "Marren");11 12 //4. 获取值的长度13 long data3 = db.StringLength("101");14 16 //5. 数值自增/减,返回自增、自减后的值17 db.StringSet("102", 10);18 //自增2,可以自增负值19 var data4 = db.StringIncrement("102", 2);20 //自减521 var data5 = db.StringDecrement("102", 5);22 24 //6. 插入实体和读取实体 (须要序列化和反序列化)25 //由于序列化的缘故原由,肯定不如存到Hash里速率快26 UserInfor userInfor = new UserInfor()27 {28 userName = "ypf",29 userPwd = "123456",30 userAge = 1531 };32 db.StringSet("userInfor_101", JsonConvert.SerializeObject(userInfor));33 UserInfor data6 = JsonConvert.DeserializeObject<UserInfor>(db.StringGet("userInfor_101"));34 35 //7. 一次性添加多个key-value凑集36 Dictionary<string, string> dic = new Dictionary<string, string>();37 dic.Add("103", Guid.NewGuid().ToString("N"));38 dic.Add("104", Guid.NewGuid().ToString("N"));39 dic.Add("105", Guid.NewGuid().ToString("N"));40 dic.Add("106", Guid.NewGuid().ToString("N"));41 dic.Add("107", Guid.NewGuid().ToString("N"));42 dic.Add("108", Guid.NewGuid().ToString("N"));43 var keyValues = dic.Select(p => new KeyValuePair<RedisKey, RedisValue>(p.Key, p.Value)).ToArray();44 bool data7 = db.StringSet(keyValues);45 46 //8.获取多个key的 value值凑集47 string[] keys = { "101", "102", "103" };48 RedisKey[] redisKeys = keys.Select(u => (RedisKey)u).ToArray();49 //此处如果是别的繁芜类型要借助JsonConvert进行转换50 List<string> data8 = db.StringGet(redisKeys).Select(u => u.ToString()).ToList();
通用Api代码:
1 //1. 删除所有数据 2 db.Execute("FLUSHDB"); 3 4 //2. 删除单个key 5 bool d1 = db.KeyDelete("101"); //删除成功,返回true 6 bool d2 = db.KeyDelete("ffff"); //删除不存在的数据,返回false 7 8 //3. 删除多个key 9 string[] arry = { "102", "103", "104" };10 RedisKey[] keys = arry.Select(u => (RedisKey)u).ToArray();11 long d3 = db.KeyDelete(keys); //返回的是删除成功的个数 12 13 //4. 判断key是否存在(不推举利用,会有并发问题)14 bool d4 = db.KeyExists("102");15 bool d5 = db.KeyExists("105");16 17 //5. 重命名key18 bool d6 = db.KeyRename("108", "10086");19 20 //6. 设置key的过期韶光(1分钟后自动销毁)21 bool d7 = db.KeyExpire("107", DateTime.Now.AddMinutes(1));
二. String类型案例1. 普通的Key-Value缓存
string类型最大略的一个运用便是Key-value缓存,value可以是大略string、int,也可以是序列化后的实体,可以替代Session进行存储,和其它缓存一样,也可以设置缓存的过期韶光(常用的键设计:表名_id ,如: UserInfor_001 )
2. 秒杀-超卖问题(1).背景
某商家拿出来100件iphone11在某天的0点以超低价开卖,势必有很多人等着购买. 大略剖析一下业务逻辑:判断库存,库存>0,连续今后实行下单逻辑(比如:插入订单表、发货地址表记录等等); 否则提示顾客“商品已经被抢光”.
看到这个需求,可能新手会直接操控关系型数据库,并没有采纳一下方法,这样就会导致同一韶光进来的顾客判断库存都>0, 购买成功的人数就>100了,也便是涌现了超卖征象,对付商家而言, 我太难了!
!
常用的办理方案:
A. 下单页面加Lock锁,会造成大量的客户等待卡去世等征象. (注:只能锁住单进程,如果是分布式,多个IIS,须要引进分布式锁)
B. 利用乐不雅观锁, 会造成一种征象纵然该用户是前100个进来的也没有买到,不合理,不适用
C. 把下单的用户加到行列步队中,然后开启其余一个线程从行列步队中读取进行下单,下单业务实行完,再出队,下单成功/失落败 利用实时通讯技能关照客户端 或者 客户端主动刷新页面进行查当作果.
(此处须要区分是出队后,接着出队,还是出队后实行完下单业务才能出下一个对呢, 还要把稳如果秒杀做事是个集群,无法担保原行列步队的顺序,且同样存在超买超卖问题)
更多C++后台开拓技能点知识内容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,音视频开拓,Linux内核,TCP/IP,协程,DPDK多个高等知识点。
C/C++后台开拓架构师免费学习地址:C/C++Linux鏈嶅姟鍣ㄥ紑鍙�/鍚庡彴鏋舵瀯甯堛€愰浂澹版暀鑲层€�-瀛︿範瑙嗛鏁欑-鑵捐璇惧爞【文章福利】其余还整理一些C++后台开拓架构师 干系学习资料,口试题,传授教化视频,以及学习路线图,免费分享有须要的可以点击 「链接」 免费领取
(2).利用Redis单线程的事理办理
事先将该商品的库存初始化到Redis中,然后利用StringDecrement自减1同时返回自减后的值,如果值>=0,表示有库存然后实行后面的下单逻辑,这里利用Redis很大程度的给关系型数据库减压了(不用查询sqlserver 判断库存了), 库存不敷,直接返回库存不敷。
(单体Redis好用,集群Redis不适用,如果用集群的话,可以考虑用lua脚本把查库存和减库存写到一起,这样就可以用于集群了)
代码分享:
1 public static void CaseDemo1(IDatabase db) 2 { 3 //删除所有数据 4 db.Execute("FLUSHDB"); 5 //事先初始化库存 6 db.StringSet("order_Num", 10); 7 8 List<Task> taskList = new List<Task>(); 9 for (int i = 0; i < 50; i++) //仿照多个用户并发10 {11 var task = Task.Run(() =>12 {13 try14 {15 //先自减,获取自减后的值16 int order_Num = (int)db.StringDecrement("order_Num", 1);17 if (order_Num >= 0)18 {19 //下面实行订单逻辑(这里不考虑业务出错的情形)20 Task.Delay(2000);21 Console.WriteLine("下单成功了");22 }23 else24 {25 Console.WriteLine("商品已经被抢光了");26 }27 28 }29 catch (Exception ex)30 {31 Console.WriteLine(ex.Message);32 throw;33 }34 });35 taskList.Add(task);36 }37 Task.WaitAll(taskList.ToArray());38 }
PS:关于秒杀问题,详见后面单独的章节:
第六节:秒杀业务/超买超卖的几种办理思路3. 点击量、点赞量、访问量
(1). 背景
要统计一个网站的访问次数,一个ip一天只能点击一次。
(2). 办理方案
先判断是否存在该ip,如果不存在,以ip为key,value随意,存储到string类型中,同时利用StringIncrement对访问次数自增1。
1 /// <summary> 2 /// 访问量案例 3 /// </summary> 4 /// <returns></returns> 5 public IActionResult Index() 6 { 7 //获取Ip,这里利用个随机数仿照ip效果 8 var ip = Guid.NewGuid().ToString("N"); 9 if (!_redis.KeyExists(ip))10 {11 //把该ip存进去,并且设置有效期为1天12 _redis.StringSet(ip, "随意值", TimeSpan.FromDays(1));13 //同时访问次数自增114 _redis.StringIncrement("fw_count", 1);15 }16 ViewBag.FwCount = _redis.StringGet("fw_count");17 return View();18 }
总结:
String除了key-value当缓存外,紧张是利用其原子性,环绕自增自减并返回当前值(计数器浸染)来利用,比如:单个网站的点击量(访问量、收藏量),单个商品的秒杀等等。如果是某个种别下多个物品的计数,同时要获取物品的计数排名,则利用SortedSet来实现,比如:某个班级每个小孩的投票数并排序、某个栏眼前每篇文章的阅读数并排序 等等。
PS:String和SortedSet具有计数器功能,String是针对单个,Sorted是针对某个种别下的多个或每一个,并且实现排序功能。 Hash类型也能实现某个种别下多个物品的计数,但它不具有排序功能。
三. Hash类型根本1.类型解释一个key,对应一个Key-Value凑集, hashid -{key:value;key:value;key:value;}, 相称于value又是一个“键值对凑集” 或者值是其余一个 Dictionary。
2. 常用指令Api3.常用Api解释(1).HashSet:存储单个 hashid-key-value
(2).HashGet:单个value的获取; 获取1个hashid对应的所有key凑集; 获取1个hashid对应所有的key和value凑集.
(3).HashDelete:删除1个hashid-key; 删除1个hashid-多个key
(4).HashIncrement:自增,返回自增后的值
(5).HashDecrement:自减,返回自减后的值
(6).HashExists:判断 hashid-key 是否存在,返回true和value
代码分享:
1 //1.添加 2 db.HashSet("UserInfor_001", "name", "ypf"); 3 db.HashSet("UserInfor_001", "age", "27"); 4 db.HashSet("UserInfor_001", "sex1", "男1"); 5 db.HashSet("UserInfor_001", "sex2", "男2"); 6 db.HashSet("UserInfor_001", "sex3", "男3"); 7 db.HashSet("UserInfor_001", "sex4", "男4"); 8 db.HashSet("UserInfor_001", "name", "Marren"); //会覆盖上面的值 9 //没找到一下把实体添加进去的方法10 UserInfor userInfor = new UserInfor()11 {12 userName = "ypf",13 userPwd = "123456",14 userAge = 1515 };16 17 //2.获取18 //2.1 单个value的获取19 string age = db.HashGet("UserInfor_001", "age");20 string name = db.HashGet("UserInfor_001", "name");21 //2.2 获取1个hashid对应所有的key的凑集(条件必须是同数据类型的)22 List<string> keyList = db.HashKeys("UserInfor_001").Select(u => (string)u).ToList();23 //2.3 获取hashid对应的所有key和value,必须担保该hashid对应的所有数据类型同等24 Dictionary<string, string> dic = new Dictionary<string, string>();25 foreach (var item in db.HashGetAll("UserInfor_001"))26 {27 dic.Add(item.Name, item.Value);28 }29 //没法一下获取一个实体30 31 //3. 删除32 //单个key33 bool d1 = db.HashDelete("UserInfor_001", "name");34 //多个key35 string[] dataKeyArry = { "sex1", "sex2", "sex3" };36 RedisValue[] redisValueArry = dataKeyArry.Select(u => (RedisValue)u).ToArray();37 long deleteNum = db.HashDelete("UserInfor_001", redisValueArry);38 39 //4. 自增,自减, 返回自增或自减后的值40 db.HashSet("UserInfor_002", "age", 20);41 long d2 = db.HashIncrement("UserInfor_002", "age", 2); //自增2,返回值为2242 long d3 = db.HashDecrement("UserInfor_002", "age", 3); //自减3,返回值为1943 44 //5. 判断数据是否存在45 bool d4 = db.HashExists("UserInfor_002", "age");46 bool d5 = db.HashExists("UserInfor_002", "age2");
4. 优缺陷
Hash类型用于存储某个种别下多个物品的存储,也可以实现物品的计数器功能,但是和SortedSet比较,它不具有排序功能。
1. 购物车剖析:
以用户id作为hashid,商品id作为key,商品数量作为value,利用自增和自减功能来实现增加商品数量和减少商品数量功能。也可以删除商品,获取商品总数,获取购物车中所有商品。
2. 存储群聊。存储群聊,比如:群名为hashid, 用户id当做key,内容作为value。 这样存储可以,但是取数据的时候必须一下全部取出来,不能根据韶光取前n条。
原文链接:https://www.cnblogs.com/yaopengfei/p/11912930.html