Redis之String类型和Hash类型的介绍和案例应用

news2024/11/17 8:50:04

一. String类型基础

1.类型介绍

  典型的Key-Value集合,如果要存实体,需要序列化成字符串,获取的时候需要反序列化一下。

2. 指令Api说明

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== 编辑

3.常用Api说明

(1).StringSet:写入数据,如果数据已经存在,则覆盖;可以一次性存入1个key-value,也可以一次性存入多个Key-value集合,并且可以设置其过期时间。

(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             //自减5
21             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 = 15
31             };
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. 重命名key
18             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++Linux服务器开发高级架构师/C++后台开发架构师​免费学习地址

【文章福利】另外还整理一些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                      try
14                      {
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                          else
24                          {
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                 //同时访问次数自增1
14                 _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. 常用指令Api

3.常用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 = 15
15             };
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             //单个key
33             bool d1 = db.HashDelete("UserInfor_001", "name");
34             //多个key
35             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,返回值为22
42             long d3 = db.HashDecrement("UserInfor_002", "age", 3); //自减3,返回值为19
43 
44             //5. 判断数据是否存在
45             bool d4 = db.HashExists("UserInfor_002", "age");
46             bool d5 = db.HashExists("UserInfor_002", "age2");

4. 优缺点

四. Hash类型案例

  Hash类型用于存储某个类别下多个物品的存储,也可以实现物品的计数器功能,但是和SortedSet相比,它不具有排序功能。

1. 购物车

分析:

以用户id作为hashid,商品id作为key,商品数量作为value,利用自增和自减功能来实现增加商品数量和减少商品数量功能。也可以删除商品,获取商品总数,获取购物车中所有商品。

2. 存储群聊消息。

存储群聊消息,比如:群名为hashid, 用户id当做key,内容作为value。 这样存储可以,但是取数据的时候必须一下全部取出来,不能根据时间取前n条。

原文链接:https://www.cnblogs.com/yaopengfei/p/11912930.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/55401.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

B2B电子商务策略[在2022年发展您的业务]

常规的电子商务商店向消费者&#xff08;B2C 或企业对消费者&#xff09;销售产品。B2B&#xff08;企业对企业&#xff09;电子商务不同于常规电子商务&#xff0c;因为 B2B电子商务的商业模式是让一家企业在线向另一家公司销售产品。 您可能会想&#xff1a;如何向企业销售比…

Windows OpenGL 图像色调

目录 一.OpenGL 图像色调调节 1.原始图片2.效果演示 二.OpenGL 图像色调调节源码下载三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 特效 零基础 OpenGL…

Ubuntu 20.04 server永久关闭swap

方法一 编辑/etc/fstab &#xff0c;sudo vim /etc/fstab&#xff0c;找到如下行 找到/dev/disk/by-uuid/28b306c5-92e4-4180-966d-cdedfbce3a4d /boot ext4 defaults 0 1 修改为如下图&#xff0c;并(/swap.img none swap sw 0 0) 将如下行注释&#…

Yolo算法检测之Anchor Boxes原理详解

刚开始yolo系列的目标检测算法&#xff0c;在一个网格中只能检测一个对象&#xff0c;但是我们在实验中发现&#xff0c;一个网格中很多时候存在不仅一个目标&#xff0c;可能存在多个目标&#xff0c;类似如下图所示&#xff0c;下面中间的网格中就存在人和车辆两个目标的中心…

嵌入式开发学习之--Git管理代码

本章主要介绍一下代码管理&#xff0c;在最后有常用的git指令&#xff0c;可以档资料收藏一下。 文章目录前言一、Github是什么二、Github的简单应用1.新建库 git init2. 添加文件 git add .2. 提交到本地仓库 git commit -m "注释"3. 创建分支 Git checkout -b [分支…

IPython工作原理

IPython工作原理 文章目录IPython是什么&#xff1f;IPython工作原理IPython控制台IPython内核实现一个简单的包装内核代码在IPython内核中的执行流程IPython是什么&#xff1f; Python最有用的功能之一就是它的交互式解释器。交互式编程允许我们非常快速地执行代码片段、测试…

[附源码]计算机毕业设计在线教育系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

详解 Intersection Observer API ( 交叉观察器 )

文章目录一、介绍二、兼容性三、内置方法/属性四、使用五、相关链接一、介绍 Intersection Observer API 提供了一种方法可以监听目标元素是否展示到视口&#xff08;viewport&#xff09;&#xff0c;常见的需求场景&#xff1a; 图片懒加载滚动动画… 上述的需求&#xff…

基于PHP+MySQL医院门诊缴费系统的设计与实现

本医院门诊缴费系统可以说是一个综合性的医院门诊缴费系统,这它包含了挂号管理,医生信息管理,药品信息管理,患者信息管理,住院信息挂了,收费信息管理等多种功能,因而具有一定的实用性。本站是一个B/S模式系统,开发采用了目前流行的PHP技术。系统界面友好,操作简单,比较实用。 本…

浅谈小程序开源业务架构建设之路

一、业务介绍 1.1 小程序开源整体介绍 百度从做智能小程序的第一天开始就打造真正开源开放的生态&#xff0c;我们的愿景是&#xff1a;定义移动时代最佳体验&#xff0c;建设智能小程序行业标准&#xff0c;打破孤岛&#xff0c;共建开源、开放、繁荣的小程序行业生态。百度…

element-ui实现一个动态布局的对话框

前言&#xff1a;在工作中有各种各样的对话框&#xff0c;最多就是填写信息这些的&#xff0c;一般这样的内容都是el-input输入框&#xff0c;el-select选择框等等之内的&#xff0c;这时我们就可以封装成一个组件&#xff0c;想要什么内容就传一个json配置&#xff0c;像其他组…

适合Python初学者阅读的Github开源代码

程序员宝藏库&#xff1a;https://gitee.com/sharetech_lee/CS-Books-Store 你想要的&#xff0c;这里都有&#xff01; Python作为一门热门的编程语言&#xff0c;在Github上想要找Python项目可以说是「多如牛毛」。 无论是Star数量还是项目数量&#xff0c;都稳居前3名。 项…

5分钟搭建一个粗粒度「视频去重」系统

Jupyter Notebook 教程: How to Build a Video Deduplication System 「视频去重」可以在海量的视频数据中实现侵权片段或者删除掉重复冗余的内容 。随着抖音、快手、Bilibili 等视频平台的兴起和火爆&#xff0c;类似视频这样的非结构化数据在数量上有了极大的增长。 视频平台…

【数据可视化】第四章—— 基于pandas的数据可视化(pandas基本操作)

图形绘制的代码&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1pgS60sry6XDILIhth8bAvA?pwdabcd 提取码&#xff1a;abcd 文章目录1. Pandas库的数据运算1.1 方法形式的运算1.2 比较运算法则1.3 排序2. 基本统计分析函数2.1 基本统计分析函数2.2 累计统计分析函数2.3 …

[附源码]计算机毕业设计JAVA学生量化考核管理系统

[附源码]计算机毕业设计JAVA学生量化考核管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM my…

基于PHP+MySQL高校毕业设计管理系统的设计与实现

直以来我国领导人提倡以人为本的治国方案,而大学是未来人才的培养基地,如何能够更好的对高校毕业设计信息进行管理,是很多高校一直在研究的一个问题,只有更加科学的对高校毕业设计信息进行管理,才能够更加积极的培养国家的栋梁之才。 管理员部分功能 1&#xff1a;教师新管理…

第二十二章《记事本》第1节:记事本项目简介

记事本软件能够打开、编辑、保存各种类型的文本文档,也能在文本文档中查找特定的关键字,此外在还能设定文本文档的字体、字号以及风格等。 22.1.1记事本功能简介 记事本软件的运行结果如图22-1所示。 图22-1记事本软件界面 从图21-1可以看到:记事本程序运行开始后,在没有…

OpenFeign动态代理、源码分析

1、OpenFeign概述 OpenFeign 组件的前身是 Netflix Feign 项目&#xff0c;由 Netflix 公司开发。后来 Feign 项目被贡献给了开源组织&#xff0c;随后Feign退出历史舞台。 OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解&#xff0c;如RequestMapping等等。O…

基于springboot的家装平台设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

牛客练习赛106 三子棋

牛客练习赛106 三子棋 2022.12.02 题目描述 给定一个 333 \times 333 的棋盘&#xff0c;共有 3393 \times 3 9339 个格子&#xff0c;初始时每个格子均没有放置棋子。 A 和 B 轮流行动&#xff0c;每次行动的人&#xff0c;必须在当前棋盘上选择一个没有放置棋子的格子…