博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redis学习系列二之.Net开发环境搭建及基础数据结构String字符串
阅读量:6153 次
发布时间:2019-06-21

本文共 12615 字,大约阅读时间需要 42 分钟。

一、简介

Redis有5种基本数据结构,分别是string、list(列表)、hash(字典)、set(集合)、zset(有序集合),这是必须掌握的5种基本数据结构.注意Redis作为一个键值对缓存系统,其所有的数据结构,都以唯一的key(字符串)作为名称,然后通过key来获取对应的数据.

 

二、.Net开发环境搭建

这个版本,暂时不考虑并发问题,后续的文章会说!

第一步:安装StackExchange.Redis包,我用的是2.0.519版本的.

第二步:编写代码,采用扩展方法的链式编程模式+async/await的编程模型

AppConfiguration.cs  全局配置类

///     /// 全局配置类    ///     public class AppConfiguration    {        ///         /// 单例实现,static关键字默认加锁        ///         static AppConfiguration()        {            Current = new AppConfiguration();        }        public static readonly AppConfiguration Current;        ///         /// 配置完Redis之后,所有需要的Redis基础服务对象,都在这里面        ///         public RedisConfigurations RedisConfigurations { get; set; }    }

FluentConfiguration.cs 链式配置核心类

///     /// 链式编程模式,扩展方法实现    ///     public static class FluentConfiguration    {        ///         /// 配置Redis        ///         /// 
/// ///
public static AppConfiguration ConfigureRedis
(this AppConfiguration configuration) where T: IRedisConfig, new() { if (configuration == null) throw new ArgumentNullException("configuration"); var config = new T(); var redisConfigurations=config.ConfigRedis(); configuration.RedisConfigurations = redisConfigurations; return configuration; } }

RedisConfigurations.cs Redis全局配置共享类

///     /// Redis配置完毕后,返回需要使用的相关对象    ///     public class RedisConfigurations    {        public IConnectionMultiplexer ConnectionMultiplexer { get; set; }    }

RedisConfig.cs Redis配置类

///     /// Redis配置类    ///     public class RedisConfig : IRedisConfig    {        ///         /// 比较耗费资源,所以写入缓存,全局共享        /// 封装了Redis基础服务对象的详细信息        ///         public static ConnectionMultiplexer ConnectionMultiplexer { get; }        ///         /// 可能存在线程安全的配置,或者只需要初始化一次的配置,放这里        ///         static RedisConfig()        {            //暂时读配置文件,后期可以用Core的配置文件系统读json文件            var redisServerAdress = ConfigurationManager.AppSettings["RedisServerAdress"];            if (string.IsNullOrEmpty(redisServerAdress))                throw new ApplicationException("配置文件中未找到RedisServer的有效配置");            ConnectionMultiplexer = ConnectionMultiplexer.Connect(redisServerAdress);        }        ///         /// 配置Redis        /// 

相关约束接口如下:

///     /// Redis配置约束    ///     public interface IRedisConfig    {        ///         /// 配置Redis        ///         RedisConfigurations ConfigRedis();    }    ///     /// Redis客户端实例约束接口    ///     public interface IRedisInstance    {    }

RedisClient.cs Redis客户端调用类

///     /// 基于async和await的异步操作的Redis客户端,有效利用CPU资源    ///     public class RedisClient: IRedisInstance    {        private static RedisConfigurations RedisConfigurations { get; }        static RedisClient()        {            RedisConfigurations=AppConfiguration.Current.RedisConfigurations;        }        ///         /// 异步,写入键值对        ///         ///         ///         /// 
public static async Task
StringSetAsync(string key,string value) { var db=GetDatabase(); return await db.StringSetAsync(key,value); } ///
/// 根据传入键,异步获取对应的值 /// ///
///
public static async Task
StringGetAsync(string key) { var db = GetDatabase(); return await db.StringGetAsync(key); } ///
/// 异步判断是否存在某个键 /// ///
///
public static async Task
KeyExistsAsync(string key) { var db = GetDatabase(); return await db.KeyExistsAsync(key); } ///
/// 异步删除某个键 /// ///
///
public static async Task
KeyDeleteAsync(string key) { var db = GetDatabase(); return await db.KeyDeleteAsync(key); } ///
/// Redis DataBase工厂方法 /// ///
private static IDatabase GetDatabase() { return RedisConfigurations.ConnectionMultiplexer.GetDatabase(); } }

暂时只扩展了一些方法,或许会持续扩展.

Program.cs 控制台入口类

class Program    {        static Program()        {            //链式配置Redis            AppConfiguration.Current.ConfigureRedis
(); } static void Main(string[] args) { StringSetGetAsync(); Console.ReadKey(); } static async void StringSetGetAsync() { if (await RedisClient.StringSetAsync("name", "xiaochao")) { Console.WriteLine("Redis中键为name的值为:{0}", await RedisClient.StringGetAsync("name")); } else { Console.WriteLine("写入异常"); } } }

ok,到这里.Net下使用StackExchange.Redis包操作Redis的环境构建完毕.

运行代码:

控制台环境:

Redis桌面管理工具

Linux下Redis-cli

后续的文章都会围绕上面三个操作方式展开.

 

三、string(字符串)

1、简单键值对操作

字符串string是Redis中最简单的数据类型,内部原理和C#的string类型一样,是一个字符数组.常见的用法是缓存一些用户数据,将用户数据序列化程Json,然后以用户Id作为键值,然后将用户数据存入Redis中.获取的时候,只需要通过用户Id去获取,然后将Json反序列化成对应的实体.

注:Redis的string类型是动态字符串,而且支持修改,这和C#中的string不一样,内部结构类似于C#中的List,有一个初始大小,如果存入string的长度大小大于string的初始大小,那么每次都会扩展1倍的大小.但是字符串最大长度只能为512MB.

代码实战:

(1)、Linux终端

(2)、C#控制台

修改控制台方法如下:

static void Main(string[] args)        {            StringSetGetAsync();            Console.ReadKey();        }        static async void StringSetGetAsync()        {            var key = "name";            if (await RedisClient.StringSetAsync(key, "xiaochao"))            {                Console.WriteLine("Redis中键为name的值为:{0}", await RedisClient.StringGetAsync(key));                if (await RedisClient.KeyExistsAsync(key))                {                    Console.WriteLine("Redis中,存在key为name的键值对");                }                if (await RedisClient.KeyDeleteAsync(key))                {                    Console.WriteLine($"删除键:{key}成功");                    if (await RedisClient.KeyExistsAsync(key))                        Console.WriteLine($"{key}存在,删除失败");                    else                        Console.WriteLine($"{key}不存在了,被删除了");                }            }            else {                Console.WriteLine("写入异常");            }        }

桌面管理工具:

 

2、批量键值对操作

C#控制台:首先引入Newtonsoft.Json包

修改RedisClient.cs如下,给它扩展两个方法

///         /// 异步批量插入键值对        ///         ///         /// 
public static async Task
StringSetAsync(KeyValuePair
[] keyValuePair) { var db = GetDatabase(); return await db.StringSetAsync(keyValuePair); } ///
/// 异步批量获取值 /// ///
///
public static async Task
StringGetAsync(RedisKey[] keys) { var db = GetDatabase(); return await db.StringGetAsync(keys); }

Program.cs如下:

class Program    {        static Program()        {            //链式配置Redis            AppConfiguration.Current.ConfigureRedis
(); } static void Main(string[] args) { StringSetGetAsync(); Console.ReadKey(); } static async void StringSetGetAsync() { var userInfos = UserInfo.UserInfos; var keyValues = new KeyValuePair
[userInfos.Count]; var keys =new RedisKey[userInfos.Count]; for (var i = 0; i < userInfos.Count; i++) { var currUserInfo = userInfos[i]; var key = currUserInfo.Id.ToString(); var value = JsonConvert.SerializeObject(currUserInfo); keyValues[i] = new KeyValuePair
(key, value); keys[i] = key; } if (await RedisClient.StringSetAsync(keyValues)) { try { var values = await RedisClient.StringGetAsync(keys); for (var i = 0; i < values.Length; i++) { Console.WriteLine(values[i]); } } //捕获辅助线程产生的异常 catch (AggregateException ex) { ex.Handle(x => { //记录日志 Console.WriteLine("异常处理完毕,批量获取值失败!"); return true; }); } } else { //记录日志 Console.WriteLine("写入异常"); } } class UserInfo { public Guid Id { get; set; } public string Name { get; set; } public int Age { get; set; } internal static List
UserInfos = new List
() { new UserInfo() { Id=Guid.NewGuid(), Name="小超", Age=23 }, new UserInfo() { Id=Guid.NewGuid(), Name="大超", Age=23 }, }; } }

(2)、管理工具

(3)、Linux终端

 

3、过期时间

Redis可以给Key设置过期时间,到达设置的时间,对应的键值对会被删除,内存会被回收,这个功能常用来控制缓存的失效时间.这里这个自动删除的机制很复杂,这里不想说太多,只介绍基本用法,后续的文章会介绍.

C#控制台,修改RedisClient.cs中的StringSetAsync方法如下:

///         /// 异步,写入键值对,可指定过期时间        ///         ///         ///         /// 过期时间        /// 
public static async Task
StringSetAsync(string key,string value, TimeSpan? expireTime=null) { var db=GetDatabase(); return await db.StringSetAsync(key,value, expireTime); }

Program.cs代码如下:

class Program    {        static Program()        {            //链式配置Redis            AppConfiguration.Current.ConfigureRedis
(); } static void Main(string[] args) { StringSetGetAsync(); Console.ReadKey(); } static async void StringSetGetAsync() { if (await RedisClient.StringSetAsync("name","xiaochao",TimeSpan.FromSeconds(2))) { Console.WriteLine("Redis中存在键为name的键值对,值为:{0}",await RedisClient.StringGetAsync("name")); await Task.Delay(2000);//模拟休息两秒 Console.WriteLine("休息两秒后,Redis的键为name的键值对:{0}", string.IsNullOrEmpty(await RedisClient.StringGetAsync("name")) ? "不存在" : "存在"); } else { //记录日志 Console.WriteLine("写入异常"); } } }

这边其它两个终端就不演示了,自行观察.

 

4、计数器

Redis提供了自增命令,前提操作的数据必须是整数,而且自增是有范围的.默认对应long的最大值,一般达不到这个值.

C#控制台:

修改RedisClient.cs下的StringSetAsync方法如下:

///         /// 异步,写入键值对,可指定过期时间        ///         ///         ///         /// 过期时间        /// 
public static async Task
StringSetAsync(string key,RedisValue value, TimeSpan? expireTime=null) { var db=GetDatabase(); return await db.StringSetAsync(key, value, expireTime); }

Program.cs代码如下:

class Program    {        static Program()        {            //链式配置Redis            AppConfiguration.Current.ConfigureRedis
(); } static void Main(string[] args) { StringSetGetAsync(); Console.ReadKey(); } static async void StringSetGetAsync() { if (await RedisClient.StringSetAsync("站点首页",0)) { //模拟用户访问 Parallel.For(0, 250000, async (i, ParallelLoopState) => { try { await RedisClient.StringIncrementAsync("站点首页"); } catch (RedisServerException ex) { //记录日志 Console.WriteLine(ex.Message); ParallelLoopState.Stop(); return; } }); //输出站点的UV Console.WriteLine(await RedisClient.StringGetAsync("站点首页")); } else { //记录日志 Console.WriteLine("写入异常"); } } }

注:这里存在两个问题,如果你把Parallel的上限值设置的过大,那么短时间内,可能Redis无法处理这么多的并发量,而报超时错误,这个时候,解决方案是使用集群或者升级虚拟机硬件配置的方式,解决这个问题,但是这里就不演示了.第二个问题是,如果把Set的初始值设为Long.MaxValue,那么Redis会报溢出错误,上面的代码已经处理.

 

转载于:https://www.cnblogs.com/GreenLeaves/p/10165352.html

你可能感兴趣的文章
Windows 8 开发之设置合约
查看>>
闲说HeartBeat心跳包和TCP协议的KeepAlive机制
查看>>
MoSQL
查看>>
Hibernate多对一外键单向关联(Annotation配置)
查看>>
《CLR via C#》读书笔记 之 方法
查看>>
设计模式:组合模式(Composite Pattern)
查看>>
ContentValues 和HashTable区别
查看>>
LogicalDOC 6.6.2 发布,文档管理系统
查看>>
给PowerShell脚本传递参数
查看>>
实战2——Hadoop的日志分析
查看>>
利用FIFO进行文件拷贝一例
查看>>
Ecshop安装过程中的的问题:cls_image::gd_version()和不支持JPEG
查看>>
resmgr:cpu quantum等待事件
查看>>
一个屌丝程序猿的人生(六十六)
查看>>
Java 编码 UTF-8
查看>>
SpringMVC实战(注解)
查看>>
关于静态属性和静态函数
查看>>
进程的基本属性:进程ID、父进程ID、进程组ID、会话和控制终端
查看>>
spring+jotm+ibatis+mysql实现JTA分布式事务
查看>>
MyBatis启动:MapperStatement创建
查看>>