在C#中使用Redis

news2024/11/27 8:28:25

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 的值设为 value
         rds.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中没有数据就执行委托(执行数据库),否则就执行rds
    T 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));

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

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

相关文章

华为云CCE集群创建loadBalancer

目录 一、目的 二、创建应用 三、创建服务 loadBalancer 四、域名解析 五、验证 一、目的 1、为CCE容器应用创建loadBalancer服务&#xff0c;并且绑定https协议的域名 2、公网访问域名: https://test.******.com 3、CCE创建用于公网域名访问的loadBalancer&#xff0c;不…

IAR9.X printf串口重定向方法,或提示Linker Error: “no definition for __write“的解决方案

一、问题现象&#xff1a; 1、Error[Li005]:no definition for"__write" [referenced from flush.o(dl7M_tlf.a)] 2、串口重映射代码没问题&#xff0c;但是串口工具接收不到数据 3、复现环境&#xff1a;IAR9.40.1 二、操作方法: 1、[工程项目]->[Options]…

【负载均衡式在线OJ】Compile_server 模块

文章目录 程序源码compile_server整体思路编译(compile.hpp)运行模块编译运行模块编译运行服务 程序源码 https://gitee.com/not-a-stupid-child/online-judge compile_server 整体思路 这个服务要对oj_server 发送过来的代码进行编译和运行&#xff0c;最后把结果返回给oj…

理想二极管

原理图 mos管选型 参考链接 很实用&#xff01;用MOS管制作一个理想中的二极管_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Xi421r7K8/?spm_id_from333.1007.tianma.2-1-4.click&vd_sourcee821a225c7ba4a7b85e5aa6d013ac92e 特此记录 anlog 2024年9月3日

JS设计模式之“单孑独立” - 单例模式

image.png 引言 在JavaScript开发中&#xff0c;单例模式是一种常见且实用的设计模式一。 单例模式的核心思想是&#xff1a;确保一个类只有一个实例对象&#xff0c;并且该对象可以在应用程序的任何地方被共享和访问。通过使用单例模式&#xff0c;我们可以简化代码、节省资…

SpringCloud开发实战(一):搭建SpringCloud框架

本系列文章主要是记录在工作中用到的微服务的各个组件&#xff0c;以及学习新的微服务组件~如有问题&#xff0c;欢迎大家批评指导。如果本文对你有帮助&#xff0c;还请点个收藏和关注。感谢支持&#xff0c;希望大家写的代码都没有BUG&#xff01;&#xff01; 前言 下面是我…

Linux下编译安装SuperLU

SuperLU用于求解大规模稀疏线性方程组&#xff0c;本文记录在远程Linux服务器下编译安装SuperLU的流程。 一、配置VS Code 2.1 安装VS Code Extensions 在本地打开VS Code, 安装以下扩展插件&#xff0c; Task Explorer Output Colorizer Git Extension Pack Remote Develop…

Stirling-PDF:基于Web的开源PDF处理工具

PDF文件进行各种各样的操作&#xff0c;比如合并、拆分、加密、解密、旋转、压缩等等&#xff0c;功能超全&#xff0c;而且开源免费&#xff0c;简直是神器&#xff01; GitHub - Stirling-Tools/Stirling-PDF: #1 Locally hosted web application that allows you to perfor…

【JAVA开源】基于Vue和SpringBoot的历史学习网站

本文项目编号 T 004 &#xff0c;文末自助获取源码 \color{red}{T004&#xff0c;文末自助获取源码} T004&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

IDEA主题的设置

目录 一、更换皮肤&#xff1a; 二、设置背景图片&#xff1a; 1.点击 File -> Settings ; 2.选择 Appearance & Behavior -> Appearance ; 一、更换皮肤&#xff1a; 1. Theme: 点击下拉框打开&#xff1b; 白色皮肤&#xff1a; inteIIiJ light Windows 10 Lig…

VirtualLab Fusion Installer-7.6.1.18 安装包 永不过期 永久使用 下载

下载地址(资源制作整理不易&#xff0c;下载使用需付费&#xff0c;不能接受请勿浪费时间下载) 链接&#xff1a;https://pan.baidu.com/s/14yJGZAosK_ftJhHD0D4VHA?pwd00zn 提取码&#xff1a;00zn

Lua:条件断点

如果有很多方式都要经过这个函数&#xff0c;但是你只需要满足其中例如参数等于Test的这一种&#xff0c;可以在断点处右键点击编辑断点打上条件断点&#xff0c;只有参数EventName等于Test的才会断上。

如何打造高校实验室预约系统?Java SpringBoot助力高效管理,MySQL存储数据,Vue前端展现,四步实现学生轻松预约!

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

【机器学习-神经网络】循环神经网络

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

Graylog配置用户权限以及常用搜索语法

文章目录 一、Graylog配置用户管理1、用户创建2、角色权限管理 二、搜索语法 基于Docker搭建Graylog的具体步骤&#xff1a; https://blog.csdn.net/weixin_44876263/article/details/141638739?spm1001.2014.3001.5502 一、Graylog配置用户管理 1、用户创建 2、角色权限管理…

Linux--实现简易shell

文章目录 shell定义和功能myshell.cGetCwd()GetUsrName()GetHostName()MakeCommandLineAndPrint()GetUserCommand()SplitCommand()Die()ExecuteCommand()GetHome()Cd()CheckBuildin()CheckRedir()myshell.c完整代码 makefile测试函数和进程之间的相似性 Shell是一个功能强大的工…

LVS之net模式实验

总结&#xff1a; lvs #配置环境&#xff0c;两个网卡 [rootlvs ~]# cd /etc/NetworkManager/system-connections/ [rootlvs system-connections]# ls ens160.nmconnection eth0.nmconnection eth1.nmconnection [rootlvs system-connections]# vim eth0.nmconnection [co…

华为OD机试 - 猜数字 - 穷举搜索(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

【RabbitMQ之一:windows环境下安装RabbitMQ】

目录 一、下载并安装Erlang1、下载Erlang2、安装Erlang3、配置环境变量4、验证erlang是否安装成功 二、下载并安装RabbitMQ1、下载RabbitMQ2、安装RabbitMQ3、配置环境变量4、验证RabbitMQ是否安装成功5、启动RabbitMQ服务&#xff08;安装后服务默认自启动&#xff09; 三、安…

Vue2转Vue3学习历程

选项式API>组合式API vue3和vue2的差别就是选项式api改为组件式api&#xff0c;就是以前vue2要定义data、method、mounted&#xff0c;在vue3就变为了更模块化的&#xff0c;并且我感觉vue3设计思路更多是以调用方法的方式实现&#xff0c;比如我实现一个方法&#xff0c;并…