当前位置: 首页 > news >正文

在C#中使用Redis

NoSql

NoSql概念

NoSQL,泛指非关系型的数据库。随着互联网web2.0网站的兴起, 历史中—中国的网站----马云--- 中国黄页,只能展示;用户只能看到 传统的关系数据库在处理web2.0网站(可以看,也可以做到写),特 别是超大规模和高并 发的SNS类型的web2.0纯动态网站已经显得力 不从心,出现了 很多难以克服的问题。 而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。 NoSQL数据库的产生就是为了解决大规模数据集合多重数据种 类带来的挑战,特别是大数据应用难题。

非关系----基本上单纯的保存数据----不支持多种数据之间的关系关系;

NoSql特点

早期: 只能存储数据在内存,性能搞,读取快,成本高; 不能固化存储;

现在:基本上也都可以固化到硬盘---也可以做到持久化存储;

Redis

什么是Redis

Remot Dictionary Server---远程字典服务器 字典:key-value

官方地址:https://redis.io/

Redis 是一种开源(BSD 许可)、内存中数据结构存储,用作数据库、缓 存和消息代理。 Redis 提供了数据结构,例如字符串、散列、列表、集合、带有范围查询的 排序集合、 位图、超级日志、地理空间索引和流。Redis 内置复制、Lua 脚本、LRU 驱 逐、事务和 不同级别的磁盘持久化,并通过Redis Sentinel 和Redis Cluster 自动分区提 供高可用性

Redis环境搭建

可以在我资料里面找Redis文件:--仅限Windows

.NET程序对接Redis

.NET 对接Redis的有三大组件 NuGet程序下载:

  1. StackExchange.Redis库(不支持哨兵,主从和集群)
  2. ServiceStack.Redis (不支持哨兵,主从和集群)
  3. CsRedis (支持哨兵,主从和集群)-首选

  1. 第一步打开Redis服务:

出现以下就是正确的:

  1. 第二步:打开Redis 客户端查看是否有效

路径:

验证:

能使用和输出就证明成功。

  1. 安装Redis可视化工具:

  1. 创建连接

测试连接Success

默认是有15个db库

刚才写的数据,就在db0里面:

Redis数据结构

五大数据结构:string(字符串),hash(哈希),list(列表),set(无序集合)及zset(有序集合)。

String类型

Key-Value存储

字符串类型是Redis中最基本的数据存储类型,它是一个由字节组成的序列,在Rediss 中是二进制安全的。这意味着该类型可以接受任何格式数据,如JPEG图像数据和Json 对象说明信息。它是标准的key-value,通常用于存储字符串、整数和浮点。Value可容 纳高达512MB的数据。 由于所有数据都在单个对象中,Redis 中的字符串操作速度非常快。基本的 Redis 命令 (如 SET、GET 和 DEL)允许您对字符串值执行基本操作。

SET 键值 – 设置指定键的值。

GET 键 – 检索指定键的值。

DEL 键 – 删除给定键的值。

在C#中使用: 安装NuGet :Caching.CSRedis 是必不可少的

"localhost,defaultDatabase=3,poolsize=3,tryit=0":连接字符串

localhost:Redis的Ip

defaultDatabase:默认是第几个库

poolsize:最大连接数量

tryit:尝试次数

string redisConnectionString = "localhost,defaultDatabase=3,poolsize=3,tryit=0";string key = "key";
using (CSRedisClient cSRedisClient = new CSRedisClient(redisConnectionString))
{cSRedisClient.Set(key, "小海study~~");string sResult = cSRedisClient.Get(key);
};

写一个父类,包含一些常用的方法和数据库连接:

 public class RedisBase{protected CSRedisClient rds = new CSRedisClient("127.0.0.1,defaultDatabase=0,poolsize=3,tryit=0");public RedisBase(){//rds.NodesServerManager.FlushAll();}/// <summary>/// 配置操作哪个节点/// </summary>/// <param name="nodeIndex"></param>public void ConfigNode(string nodeIndex){}/// <summary>/// 删除所有节点信息/// </summary>public void FlushAll(){rds.NodesServerManager.FlushAll();}}

应用程序场景:非常常见的场景用于计算站点访问量、当前在线人数等

秒杀案例:

超卖:订单数超过商品

秒杀:10件商品,大用户量的来参与秒杀,同时来抢这个商品; 肯定是多个线程同时来操作

如果商品保存在数据库中:

程序设计:a.获取商品数量 b.判断是否还有库存 c.如果有库存---提示秒杀成功--减库存 d.库存再设置上去

注意:防止超卖---10商品参与秒杀,如果下了20个订单~~

public class OversellTest : RedisBase
{private static object Object_locker = new object();public void Show(){int count = 10; //初始化有10件商品//应为是秒杀,并发很高~~ 多线程~~ //如果秒杀成功---必然要减库存~~List<Task> tasklist = new List<Task>();for (int i = 0; i < 5000; i++){tasklist.Add(Task.Run(() =>{int k = i;//判断仓库数据量和减库存必须是原子性操作;原子的:不能拆分; lock (Object_locker){if (count > 0) //获取库存,判断是否还有库存{//Thread.Sleep(new Random().Next(10, 30)); //随机休息  count = count - 1;  //减库存Console.WriteLine($"用户{k}参与秒杀,秒杀成功了。。。");}else{Console.WriteLine($"秒杀结束了...count值:{count}");}}}));}Task.WaitAll(tasklist.ToArray());Console.WriteLine($"所有秒杀结束后,库存应该为0 ,这里的Count:{count}");}private static bool IsGoOn = true;//秒杀活动是否结束public void ShowRedis(){FlushAll();rds.Set("Stock", 10);  //初始化商品的库存量for (int i = 0; i < 5000; i++){int k = i;Task.Run(() =>//每个线程就是一个用户请求{if (IsGoOn){//long index = rds.IncrBy("Stock", -1); //自减1并且返回  ---这个是原则性操作,不会出现中间值; 不会有超卖问题if (index >= 0){Console.WriteLine($"{k.ToString("000")}秒杀成功,秒杀商品索引为{index}");}else{if (IsGoOn){IsGoOn = false;}Console.WriteLine($"{k.ToString("000")}秒杀失败,秒杀商品索引为{index}");}}else{Console.WriteLine($"{k.ToString("000")}秒杀停止......");}});}Console.Read();}
}

Hash类型

Key-Value存储

Redis hash 是一个键值(key=>value)对集合。Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。Redis的Hash结构可以使你像在数据库 中Update一个属性一样只修改某一项属性值。和String略像,但value中存放的是一张表, 一般用于多个个体的详细事项排列,String也可以做到,但要比hash麻烦许多。 哈希命令允许您独立访问和更改单个或多个字段。

HSET – 将值映射到哈希中的键。

HGET – 检索与哈希中的键关联的各个值。

HGETALL – 显示整个哈希内容。

HDEL – 从哈希中删除现有的键值对。

Hash二次封装:

 public class RedisHashService : RedisBase{#region Hash/// <summary>/// [redis-server 3.2.0] 返回hash指定field的value的字符串长度,如果hash或者field不存在,返回0./// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="field">字段</param>/// <returns></returns>public long HStrLen(string key, string field) => rds.HStrLen(key, field);/// <summary>/// 删除一个或多个哈希表字段/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="fields">字段</param>/// <returns></returns>public long HDel(string key, params string[] fields) => rds.HDel(key, fields);/// <summary>/// 查看哈希表 key 中,指定的字段是否存在/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="field">字段</param>/// <returns></returns>public bool HExists(string key, string field) => rds.HExists(key, field);/// <summary>/// 获取存储在哈希表中指定字段的值/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="field">字段</param>/// <returns></returns>public string HGet(string key, string field) => rds.HGet(key, field);/// <summary>/// 获取存储在哈希表中指定字段的值/// </summary>/// <typeparam name="T">byte[] 或其他类型</typeparam>/// <param name="key">不含prefix前辍</param>/// <param name="field">字段</param>/// <returns></returns>public T HGet<T>(string key, string field) => rds.HGet<T>(key, field);/// <summary>/// 获取在哈希表中指定 key 的所有字段和值/// </summary>/// <param name="key">不含prefix前辍</param>/// <returns></returns>public Dictionary<string, string> HGetAll(string key) => rds.HGetAll(key);/// <summary>/// 获取在哈希表中指定 key 的所有字段和值/// </summary>/// <typeparam name="T">byte[] 或其他类型</typeparam>/// <param name="key">不含prefix前辍</param>/// <returns></returns>public Dictionary<string, T> HGetAll<T>(string key) => rds.HGetAll<T>(key);/// <summary>/// 为哈希表 key 中的指定字段的整数值加上增量 increment/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="field">字段</param>/// <param name="value">增量值(默认=1)</param>/// <returns></returns>public long HIncrBy(string key, string field, long value = 1) => rds.HIncrBy(key, field, value);/// <summary>/// 为哈希表 key 中的指定字段的整数值加上增量 increment/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="field">字段</param>/// <param name="value">增量值(默认=1)</param>/// <returns></returns>public decimal HIncrByFloat(string key, string field, decimal value) => rds.HIncrByFloat(key, field, value);/// <summary>/// 获取所有哈希表中的字段/// </summary>/// <param name="key">不含prefix前辍</param>/// <returns></returns>public string[] HKeys(string key) => rds.HKeys(key);/// <summary>/// 获取哈希表中字段的数量/// </summary>/// <param name="key">不含prefix前辍</param>/// <returns></returns>public long HLen(string key) => rds.HLen(key);/// <summary>/// 获取存储在哈希表中多个字段的值/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="fields">字段</param>/// <returns></returns>public string[] HMGet(string key, params string[] fields) => rds.HMGet(key, fields);/// <summary>/// 获取存储在哈希表中多个字段的值/// </summary>/// <typeparam name="T">byte[] 或其他类型</typeparam>/// <param name="key">不含prefix前辍</param>/// <param name="fields">一个或多个字段</param>/// <returns></returns>public T[] HMGet<T>(string key, params string[] fields) => rds.HMGet<T>(key, fields);/// <summary>/// 同时将多个 field-value (域-值)对设置到哈希表 key 中/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="keyValues">key1 value1 [key2 value2]</param>/// <returns></returns>public bool HMSet(string key, params object[] keyValues){return rds.HMSet(key, keyValues);}/// <summary>/// 将哈希表 key 中的字段 field 的值设为 value/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="field">字段</param>/// <param name="value">值</param>/// <returns>如果字段是哈希表中的一个新建字段,并且值设置成功,返回true。如果哈希表中域字段已经存在且旧值已被新值覆盖,返回false。</returns>public bool HSet(string key, string field, object value){return rds.HSet(key, field, value);}/// <summary>/// 只有在字段 field 不存在时,设置哈希表字段的值/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="field">字段</param>/// <param name="value">值(string 或 byte[])</param>/// <returns></returns>public bool HSetNx(string key, string field, object value){return rds.HSetNx(key, field, value);}/// <summary>/// 获取哈希表中所有值/// </summary>/// <param name="key">不含prefix前辍</param>/// <returns></returns>public string[] HVals(string key) => rds.HVals(key);/// <summary>/// 获取哈希表中所有值/// </summary>/// <typeparam name="T">byte[] 或其他类型</typeparam>/// <param name="key">不含prefix前辍</param>/// <returns></returns>public T[] HVals<T>(string key) => rds.HVals<T>(key);/// <summary>/// 迭代哈希表中的键值对/// </summary>/// <param name="key">不含prefix前辍</param>/// <param name="cursor">位置</param>/// <param name="pattern">模式</param>/// <param name="count">数量</param>/// <returns></returns>public RedisScan<(string field, string value)> HScan(string key, long cursor, string pattern = null, long? count = null){return rds.HScan(key, cursor, pattern, count);}/// <summary>/// 迭代哈希表中的键值对/// </summary>/// <typeparam name="T">byte[] 或其他类型</typeparam>/// <param name="key">不含prefix前辍</param>/// <param name="cursor">位置</param>/// <param name="pattern">模式</param>/// <param name="count">数量</param>/// <returns></returns>public RedisScan<(string field, T value)> HScan<T>(string key, long cursor, string pattern = null, long? count = null){return rds.HScan<T>(key, cursor, pattern, count);}#endregion}

常见的使用:

 RedisHashService rds = new RedisHashService();{rds.FlushAll();{// 同时将多个 field-value (域-值)对设置到哈希表 key 中rds.HMSet("TestHDel", "string1", "name", "bytes1", "25", "class1", new UserInfo() { Name = "XiaoHai", Id = 123 });//删除一个或多个哈希表字段rds.HDel("TestHDel", "string1", "bytes1", "class1");// 查看哈希表 key 中,指定的字段是否存在bool exists = rds.HExists("TestHExists", "null1");Console.WriteLine(exists);//将哈希表 key 中的字段 field 的值设为 valuerds.HSet("TestHExists", "null1", 1);//查看哈希表 key 中,指定的字段是否存在exists = rds.HExists("TestHExists", "null1");Console.WriteLine(exists);//删除一个或多个哈希表字段rds.HDel("TestHExists", "null1");//查看哈希表 key 中,指定的字段是否存在exists = rds.HExists("TestHExists", "null1");}{string result1 = rds.HGet("TestHGet", "null1");}}

应用程序场景:存储部分更改数据,如用户信息、会话共享。

因为在使用Redis的时候,尽可能的去完成原子性操作,对于一个业务处理,尽量不要去搞多个操作;

Redis在WPF中的应用

缓存数据

在需要的ViewModel中集成RedisBase

在RedisBase中封装为一个通用的方法:

/// <summary>
/// 优先获取redis中的数据,如果没有想要获取的数据的数据,就执行委托
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="key">redis的key</param>
/// <param name="func">包装查询数据库的逻辑</param>
/// <returns></returns>
protected T GetCacheData<T>(string key,Func<T> func) where T : class
{// 如果rds中没有数据就执行委托(执行数据库),否则就执行rdsT t = rds.Get<T>(key);if (t == null) // redis里面没有数据{t = func.Invoke();rds.Set(key, t);}return t;
}

然后再ViewModel中调用这个方法:


List<ScoreInfo> scoreList = new List<ScoreInfo>();
string key = "scoreList";
scoreList = GetCacheData(key, () =>
{return _scoreInfoService.Set<ScoreInfo>().ToList();
});ScoreList.Clear();
//赋值
scoreList.ForEach(x => ScoreList.Add(x));

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 虚幻5|知识点(1)寻找查看旋转,击打敌人后朝向主角
  • MySQL笔记(大斌)
  • Python世界:文件自动化备份实践
  • 聚类算法-Kmeans聚类
  • 基础闯关4
  • CentOS7虚拟机下安装及使用Docker
  • qt5.15.2在线安装选项不见了?怎么办?
  • 【Pythonj进阶】Python中的日志记录与监控:跟踪和分析应用程序行为
  • union 的正确食用方法
  • 文件包含漏洞PHP伪协议利用方法
  • Mac 安装 jdk 8详细教程
  • 有限体积法:基于一维稳态扩散问题及其程序实现
  • 计算机网络 第2章 物理层
  • 农产品自主供销系统小程序的设计
  • 94.游戏的启动与多开-互斥量对开检测
  • (三)从jvm层面了解线程的启动和停止
  • 【Amaple教程】5. 插件
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • CentOS 7 修改主机名
  • CentOS6 编译安装 redis-3.2.3
  • Date型的使用
  • Git同步原始仓库到Fork仓库中
  • JS专题之继承
  • node入门
  • spring-boot List转Page
  • Wamp集成环境 添加PHP的新版本
  • windows下mongoDB的环境配置
  • 从tcpdump抓包看TCP/IP协议
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 前端路由实现-history
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 思维导图—你不知道的JavaScript中卷
  • # Redis 入门到精通(一)数据类型(4)
  • #if 1...#endif
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (14)Hive调优——合并小文件
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (Oracle)SQL优化基础(三):看懂执行计划顺序
  • (附源码)ssm码农论坛 毕业设计 231126
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (四)stm32之通信协议
  • (学习日记)2024.02.29:UCOSIII第二节
  • (一)u-boot-nand.bin的下载
  • (转)http协议
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • .CSS-hover 的解释
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .Net mvc总结
  • .NET 的静态构造函数是否线程安全?答案是肯定的!