Cache和NoSql、Redis![](https://img2020.cnblogs.com/i-beta/539967/202003/539967-20200315154111909-921507929.png)
ServiceStack.Redis
下面额代码类均是通过 ServiceStack.Redis 来对Redis进行各种操作
redis 文件配置类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// redis配置文件信息 /// 也可以放到配置文件去 /// </summary> public sealed class RedisConfigInfo { /// <summary> /// 可写的Redis链接地址 /// format:ip1,ip2 /// /// 默认6379端口 /// </summary> public string WriteServerList = "127.0.0.1:6379"; /// <summary> /// 可读的Redis链接地址 /// format:ip1,ip2 /// </summary> public string ReadServerList = "127.0.0.1:6379"; /// <summary> /// 最大写链接数 /// </summary> public int MaxWritePoolSize = 60; /// <summary> /// 最大读链接数 /// </summary> public int MaxReadPoolSize = 60; /// <summary> /// 本地缓存到期时间,单位:秒 /// </summary> public int LocalCacheTime = 180; /// <summary> /// 自动重启 /// </summary> public bool AutoStart = true; /// <summary> /// 是否记录日志,该设置仅用于排查redis运行时出现的问题, /// 如redis工作正常,请关闭该项 /// </summary> public bool RecordeLog = false; }
redis操作的基类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// RedisBase类,是redis操作的基类,继承自IDisposable接口,主要用于释放内存 /// </summary> public abstract class RedisBase : IDisposable { public IRedisClient iClient { get; private set; } /// <summary> /// 构造时完成链接的打开 /// </summary> public RedisBase() { iClient = RedisManager.GetClient(); } //public static IRedisClient iClient { get; private set; } //static RedisBase() //{ // iClient = RedisManager.GetClient(); //} private bool _disposed = false; protected virtual void Dispose(bool disposing) { if (!this._disposed) { if (disposing) { iClient.Dispose(); iClient = null; } } this._disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void Transcation() { using (IRedisTransaction irt = this.iClient.CreateTransaction()) { try { irt.QueueCommand(r => r.Set("key", 20)); irt.QueueCommand(r => r.Increment("key", 1)); irt.Commit(); // 提交事务 } catch (Exception ex) { irt.Rollback(); throw ex; } } } /// <summary> /// 清除全部数据 请小心 /// </summary> public virtual void FlushAll() { iClient.FlushAll(); } /// <summary> /// 保存数据DB文件到硬盘 /// </summary> public void Save() { iClient.Save();//阻塞式save } /// <summary> /// 异步保存数据DB文件到硬盘 /// </summary> public void SaveAsync() { iClient.SaveAsync();//异步save } }
Redis管理中心
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Redis管理中心 /// </summary> public class RedisManager { /// <summary> /// redis配置文件信息 /// </summary> private static RedisConfigInfo RedisConfigInfo = new RedisConfigInfo(); /// <summary> /// Redis客户端池化管理 /// </summary> private static PooledRedisClientManager prcManager; /// <summary> /// 静态构造方法,初始化链接池管理对象 /// </summary> static RedisManager() { CreateManager(); } /// <summary> /// 创建链接池管理对象 /// </summary> private static void CreateManager() { string[] WriteServerConStr = RedisConfigInfo.WriteServerList.Split(','); string[] ReadServerConStr = RedisConfigInfo.ReadServerList.Split(','); prcManager = new PooledRedisClientManager(ReadServerConStr, WriteServerConStr, new RedisClientManagerConfig { MaxWritePoolSize = RedisConfigInfo.MaxWritePoolSize, MaxReadPoolSize = RedisConfigInfo.MaxReadPoolSize, AutoStart = RedisConfigInfo.AutoStart, }); } /// <summary> /// 客户端缓存操作对象 /// </summary> public static IRedisClient GetClient() { return prcManager.GetClient(); } }
String
redis 的string类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// key-value 键值对:value可以是序列化的数据 /// </summary> public class RedisStringService : RedisBase { #region 赋值 /// <summary> /// 设置key的value /// </summary> public bool Set<T>(string key, T value) { return base.iClient.Set<T>(key, value); } /// <summary> /// 设置key的value并设置过期时间 /// </summary> public bool Set<T>(string key, T value, DateTime dt) { return base.iClient.Set<T>(key, value, dt); } /// <summary> /// 设置key的value并设置过期时间 /// </summary> public bool Set<T>(string key, T value, TimeSpan sp) { return base.iClient.Set<T>(key, value, sp); } /// <summary> /// 设置多个key/value /// </summary> public void Set(Dictionary<string, string> dic) { base.iClient.SetAll(dic); } #endregion #region 追加 /// <summary> /// 在原有key的value值之后追加value,没有就新增一项 /// </summary> public long Append(string key, string value) { return base.iClient.AppendToValue(key, value); } #endregion #region 获取值 /// <summary> /// 获取key的value值 /// </summary> public string Get(string key) { return base.iClient.GetValue(key); } /// <summary> /// 获取多个key的value值 /// </summary> public List<string> Get(List<string> keys) { return base.iClient.GetValues(keys); } /// <summary> /// 获取多个key的value值 /// </summary> public List<T> Get<T>(List<string> keys) { return base.iClient.GetValues<T>(keys); } #endregion #region 获取旧值赋上新值 /// <summary> /// 获取旧值赋上新值 /// </summary> public string GetAndSetValue(string key, string value) { return base.iClient.GetAndSetValue(key, value); } #endregion #region 辅助方法 /// <summary> /// 获取值的长度 /// </summary> public long GetLength(string key) { return base.iClient.GetStringCount(key); } /// <summary> /// 自增1,返回自增后的值 /// </summary> public long Incr(string key) { return base.iClient.IncrementValue(key); } /// <summary> /// 自增count,返回自增后的值 /// </summary> public long IncrBy(string key, int count) { return base.iClient.IncrementValueBy(key, count); } /// <summary> /// 自减1,返回自减后的值 /// </summary> public long Decr(string key) { return base.iClient.DecrementValue(key); } /// <summary> /// 自减count ,返回自减后的值 /// </summary> /// <param name="key"></param> /// <param name="count"></param> /// <returns></returns> public long DecrBy(string key, int count) { return base.iClient.DecrementValueBy(key, count); } #endregion }
使用
using (RedisStringService service = new RedisStringService()) { service.Set<string>("student1", "梦的翅膀"); Console.WriteLine(service.Get("student1")); service.Append("student1", "20180802"); Console.WriteLine(service.Get("student1")); Console.WriteLine(service.GetAndSetValue("student1", "程序错误")); Console.WriteLine(service.Get("student1")); service.Set<string>("student2", "王", DateTime.Now.AddSeconds(5)); Thread.Sleep(5100); Console.WriteLine(service.Get("student2")); service.Set<int>("Age", 32); Console.WriteLine(service.Incr("Age")); Console.WriteLine(service.IncrBy("Age", 3)); Console.WriteLine(service.Decr("Age")); Console.WriteLine(service.DecrBy("Age", 3)); }
超卖
/// <summary> /// 超卖:订单数超过商品 /// ///数据库:秒杀的时候,10件商品,100个人想买,假定大家一瞬间都来了, ///A 查询还有没有--有---1更新 ///B 查询还有没有--有---1更新 ///C 查询还有没有--有---1更新 ///可能会卖出12 12甚至20件商品 /// /// 微服务也有超卖的问题,异步队列 /// /// /// Redis原子性操作--保证一个数值只出现一次--防止一个商品卖给多个人 /// /// /// Redis是单线程,程序怎么又多线程操作Redis呢? 这个是可以的, /// 打开多个链接,去提交任务,对程序而言,Redis是并发 /// /// 假如redis命令是拼装的,Decr---1 获取值 2 程序减1 3 再save结果回去 /// 程序多线程并发一下, A线程 1 2 3 初始值是10 /// B线程 1 2 3 结果是9,减了2次但是结果是9 /// /// 组合命令,Decr Redis线程直接完成当前值-1并返回结果,原子性操作 /// 程序多线程并发一下,A线程 123 初始值10 /// B线程 123 /// C线程 123 得到3个结果,9/8/7 /// /// 假如库存只有1个(数据库),三个人同时来下单,一检测>0,都会成功--超卖 /// 三个人同时来,lock/开启事务 /// 只有一个人能去检测>0 -1 save /// 然后第二个人来,==0 返回失败 /// 然后第三个人来,==0 返回失败 /// 因为这个等于是数据库单线程了,其他都要阻塞,各种超时 /// -1的时候除了操作库存,还得增加订单,等支付。。 /// 10个商品秒杀,一次只能进一个? 违背了业务 /// /// 所以用上了Redis,一方面保证绝对不会超卖, /// 另一方面没有效率影响,数据库是可以为成功的人并发的 /// 还有撤单的时候增加库存,可以继续秒杀, /// 限制秒杀的库存是放在redis,不是数据库,不会造成数据的不一致性 /// /// Redis能够拦截无效的请求,如果没有这一层,所有的请求压力都到数据库 /// /// 缓存击穿/穿透---缓存down掉,请求全部到数据库 /// 缓存预热功能---缓存重启,数据丢失,多了一个初始化缓存数据动作(写代码去把数据读出来放入缓存)
模拟超卖现象
public class OversellField { private static bool IsGoOn = true;//秒杀活动是否结束 private static int Stock = 0; public static void Show() { Stock = 10; for (int i = 0; i < 5000; i++) { int k = i; Task.Run(() =>//每个线程就是一个用户请求 { if (IsGoOn) { long index = Stock;//-1并且返回 去数据库查一下当前的库存 Thread.Sleep(100); if (index >= 1) { Stock = Stock - 1;//更新库存 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(); } }
利用redis解决超卖问题
public class OversellTest { private static bool IsGoOn = true;//秒杀活动是否结束 public static void Show() { using (RedisStringService service = new RedisStringService()) { service.Set<int>("Stock", 10);//是库存 } for (int i = 0; i < 5000; i++) { int k = i; Task.Run(() =>//每个线程就是一个用户请求 { using (RedisStringService service = new RedisStringService()) { if (IsGoOn) { long index = service.Decr("Stock");//-1并且返回 if (index >= 0) { Console.WriteLine($"{k.ToString("000")}秒杀成功,秒杀商品索引为{index}"); //service.Incr("Stock");//+1 //可以分队列,去数据库操作 } else { if (IsGoOn) { IsGoOn = false; } Console.WriteLine($"{k.ToString("000")}秒杀失败,秒杀商品索引为{index}"); } } else { Console.WriteLine($"{k.ToString("000")}秒杀停止......"); } } }); } Console.Read(); } }
Hashtable
redis 的Hash类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Hash:类似dictionary,通过索引快速定位到指定元素的,耗时均等,跟string的区别在于不用反序列化,直接修改某个字段 /// string的话要么是 001:序列化整个实体 /// 要么是 001_name: 001_pwd: 多个key-value /// Hash的话,一个hashid-{key:value;key:value;key:value;} /// 可以一次性查找实体,也可以单个,还可以单个修改 /// </summary> public class RedisHashService : RedisBase { #region 添加 /// <summary> /// 向hashid集合中添加key/value /// </summary> public bool SetEntryInHash(string hashid, string key, string value) { return base.iClient.SetEntryInHash(hashid, key, value); } /// <summary> /// 如果hashid集合中存在key/value则不添加返回false, /// 如果不存在在添加key/value,返回true /// </summary> public bool SetEntryInHashIfNotExists(string hashid, string key, string value) { return base.iClient.SetEntryInHashIfNotExists(hashid, key, value); } /// <summary> /// 存储对象T t到hash集合中 /// 需要包含Id,然后用Id获取 /// </summary> public void StoreAsHash<T>(T t) { base.iClient.StoreAsHash<T>(t); } #endregion #region 获取 /// <summary> /// 获取对象T中ID为id的数据。 /// </summary> public T GetFromHash<T>(object id) { return base.iClient.GetFromHash<T>(id); } /// <summary> /// 获取所有hashid数据集的key/value数据集合 /// </summary> public Dictionary<string, string> GetAllEntriesFromHash(string hashid) { return base.iClient.GetAllEntriesFromHash(hashid); } /// <summary> /// 获取hashid数据集中的数据总数 /// </summary> public long GetHashCount(string hashid) { return base.iClient.GetHashCount(hashid); } /// <summary> /// 获取hashid数据集中所有key的集合 /// </summary> public List<string> GetHashKeys(string hashid) { return base.iClient.GetHashKeys(hashid); } /// <summary> /// 获取hashid数据集中的所有value集合 /// </summary> public List<string> GetHashValues(string hashid) { return base.iClient.GetHashValues(hashid); } /// <summary> /// 获取hashid数据集中,key的value数据 /// </summary> public string GetValueFromHash(string hashid, string key) { return base.iClient.GetValueFromHash(hashid, key); } /// <summary> /// 获取hashid数据集中,多个keys的value集合 /// </summary> public List<string> GetValuesFromHash(string hashid, string[] keys) { return base.iClient.GetValuesFromHash(hashid, keys); } #endregion #region 删除 /// <summary> /// 删除hashid数据集中的key数据 /// </summary> public bool RemoveEntryFromHash(string hashid, string key) { return base.iClient.RemoveEntryFromHash(hashid, key); } #endregion #region 其它 /// <summary> /// 判断hashid数据集中是否存在key的数据 /// </summary> public bool HashContainsEntry(string hashid, string key) { return base.iClient.HashContainsEntry(hashid, key); } /// <summary> /// 给hashid数据集key的value加countby,返回相加后的数据 /// </summary> public double IncrementValueInHash(string hashid, string key, double countBy) { return base.iClient.IncrementValueInHash(hashid, key, countBy); } #endregion }
使用
Console.WriteLine("*****************************************"); { using (RedisHashService service = new RedisHashService()) { service.SetEntryInHash("student", "id", "123456"); service.SetEntryInHash("student", "name", "张xx"); service.SetEntryInHash("student", "remark", "高级班的学员"); var keys = service.GetHashKeys("student"); var values = service.GetHashValues("student"); var keyValues = service.GetAllEntriesFromHash("student"); Console.WriteLine(service.GetValueFromHash("student", "id")); service.SetEntryInHashIfNotExists("student", "name", "太子爷"); service.SetEntryInHashIfNotExists("student", "description", "高级班的学员2"); Console.WriteLine(service.GetValueFromHash("student", "name")); Console.WriteLine(service.GetValueFromHash("student", "description")); service.RemoveEntryFromHash("student", "description"); Console.WriteLine(service.GetValueFromHash("student", "description")); } }
Set
redis 的Set类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Set:用哈希表来保持字符串的唯一性,没有先后顺序,存储一些集合性的数据 /// 1.共同好友、二度好友 /// 2.利用唯一性,可以统计访问网站的所有独立 IP /// </summary> public class RedisSetService : RedisBase { #region 添加 /// <summary> /// key集合中添加value值 /// </summary> public void Add(string key, string value) { base.iClient.AddItemToSet(key, value); } /// <summary> /// key集合中添加list集合 /// </summary> public void Add(string key, List<string> list) { base.iClient.AddRangeToSet(key, list); } #endregion #region 获取 /// <summary> /// 随机获取key集合中的一个值 /// </summary> public string GetRandomItemFromSet(string key) { return base.iClient.GetRandomItemFromSet(key); } /// <summary> /// 获取key集合值的数量 /// </summary> public long GetCount(string key) { return base.iClient.GetSetCount(key); } /// <summary> /// 获取所有key集合的值 /// </summary> public HashSet<string> GetAllItemsFromSet(string key) { return base.iClient.GetAllItemsFromSet(key); } #endregion #region 删除 /// <summary> /// 随机删除key集合中的一个值 /// </summary> public string RandomRemoveItemFromSet(string key) { return base.iClient.PopItemFromSet(key); } /// <summary> /// 删除key集合中的value /// </summary> public void RemoveItemFromSet(string key, string value) { base.iClient.RemoveItemFromSet(key, value); } #endregion #region 其它 /// <summary> /// 从fromkey集合中移除值为value的值,并把value添加到tokey集合中 /// </summary> public void MoveBetweenSets(string fromkey, string tokey, string value) { base.iClient.MoveBetweenSets(fromkey, tokey, value); } /// <summary> /// 返回keys多个集合中的并集,返还hashset /// </summary> public HashSet<string> GetUnionFromSets(params string[] keys) { return base.iClient.GetUnionFromSets(keys); } /// <summary> /// 返回keys多个集合中的交集,返还hashset /// </summary> public HashSet<string> GetIntersectFromSets(params string[] keys) { return base.iClient.GetIntersectFromSets(keys); } /// <summary> /// 返回keys多个集合中的差集,返还hashset /// </summary> /// <param name="fromKey">原集合</param> /// <param name="keys">其他集合</param> /// <returns>出现在原集合,但不包含在其他集合</returns> public HashSet<string> GetDifferencesFromSet(string fromKey, params string[] keys) { return base.iClient.GetDifferencesFromSet(fromKey,keys); } /// <summary> /// keys多个集合中的并集,放入newkey集合中 /// </summary> public void StoreUnionFromSets(string newkey, string[] keys) { base.iClient.StoreUnionFromSets(newkey, keys); } /// <summary> /// 把fromkey集合中的数据与keys集合中的数据对比,fromkey集合中不存在keys集合中,则把这些不存在的数据放入newkey集合中 /// </summary> public void StoreDifferencesFromSet(string newkey, string fromkey, string[] keys) { base.iClient.StoreDifferencesFromSet(newkey, fromkey, keys); } #endregion }
使用
Console.WriteLine("*****************************************"); { using (RedisSetService service = new RedisSetService()) { service.FlushAll();//清理全部数据 service.Add("advanced", "111"); service.Add("advanced", "112"); service.Add("advanced", "114"); service.Add("advanced", "114"); service.Add("advanced", "115"); service.Add("advanced", "115"); service.Add("advanced", "113"); var result = service.GetAllItemsFromSet("advanced"); var random = service.GetRandomItemFromSet("advanced");//随机获取 service.GetCount("advanced");//独立的ip数 service.RemoveItemFromSet("advanced", "114"); { service.Add("begin", "111"); service.Add("begin", "112"); service.Add("begin", "115"); service.Add("end", "111"); service.Add("end", "114"); service.Add("end", "113"); var result1 = service.GetIntersectFromSets("begin", "end"); var result2 = service.GetDifferencesFromSet("begin", "end"); var result3 = service.GetUnionFromSets("begin", "end"); //共同好友 共同关注 } } }
去重验证
删除Item验证
集合的交差并
ZSet
redis 的zset类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Sorted Sets是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列 /// 1.带有权重的元素,比如一个游戏的用户得分排行榜 /// 2.比较复杂的数据结构,一般用到的场景不算太多 /// </summary> public class RedisZSetService : RedisBase { #region 添加 /// <summary> /// 添加key/value,默认分数是从1.多*10的9次方以此递增的,自带自增效果 /// </summary> public bool Add(string key, string value) { return base.iClient.AddItemToSortedSet(key, value); } /// <summary> /// 添加key/value,并设置value的分数 /// </summary> public bool AddItemToSortedSet(string key, string value, double score) { return base.iClient.AddItemToSortedSet(key, value, score); } /// <summary> /// 为key添加values集合,values集合中每个value的分数设置为score /// </summary> public bool AddRangeToSortedSet(string key, List<string> values, double score) { return base.iClient.AddRangeToSortedSet(key, values, score); } /// <summary> /// 为key添加values集合,values集合中每个value的分数设置为score /// </summary> public bool AddRangeToSortedSet(string key, List<string> values, long score) { return base.iClient.AddRangeToSortedSet(key, values, score); } #endregion #region 获取 /// <summary> /// 获取key的所有集合 /// </summary> public List<string> GetAll(string key) { return base.iClient.GetAllItemsFromSortedSet(key); } /// <summary> /// 获取key的所有集合,倒叙输出 /// </summary> public List<string> GetAllDesc(string key) { return base.iClient.GetAllItemsFromSortedSetDesc(key); } /// <summary> /// 获取集合,带分数 /// </summary> public IDictionary<string, double> GetAllWithScoresFromSortedSet(string key) { return base.iClient.GetAllWithScoresFromSortedSet(key); } /// <summary> /// 获取key为value的下标值 /// </summary> public long GetItemIndexInSortedSet(string key, string value) { return base.iClient.GetItemIndexInSortedSet(key, value); } /// <summary> /// 倒叙排列获取key为value的下标值 /// </summary> public long GetItemIndexInSortedSetDesc(string key, string value) { return base.iClient.GetItemIndexInSortedSetDesc(key, value); } /// <summary> /// 获取key为value的分数 /// </summary> public double GetItemScoreInSortedSet(string key, string value) { return base.iClient.GetItemScoreInSortedSet(key, value); } /// <summary> /// 获取key所有集合的数据总数 /// </summary> public long GetSortedSetCount(string key) { return base.iClient.GetSortedSetCount(key); } /// <summary> /// key集合数据从分数为fromscore到分数为toscore的数据总数 /// </summary> public long GetSortedSetCount(string key, double fromScore, double toScore) { return base.iClient.GetSortedSetCount(key, fromScore, toScore); } /// <summary> /// 获取key集合从高分到低分排序数据,分数从fromscore到分数为toscore的数据 /// </summary> public List<string> GetRangeFromSortedSetByHighestScore(string key, double fromscore, double toscore) { return base.iClient.GetRangeFromSortedSetByHighestScore(key, fromscore, toscore); } /// <summary> /// 获取key集合从低分到高分排序数据,分数从fromscore到分数为toscore的数据 /// </summary> public List<string> GetRangeFromSortedSetByLowestScore(string key, double fromscore, double toscore) { return base.iClient.GetRangeFromSortedSetByLowestScore(key, fromscore, toscore); } /// <summary> /// 获取key集合从高分到低分排序数据,分数从fromscore到分数为toscore的数据,带分数 /// </summary> public IDictionary<string, double> GetRangeWithScoresFromSortedSetByHighestScore(string key, double fromscore, double toscore) { return base.iClient.GetRangeWithScoresFromSortedSetByHighestScore(key, fromscore, toscore); } /// <summary> /// 获取key集合从低分到高分排序数据,分数从fromscore到分数为toscore的数据,带分数 /// </summary> public IDictionary<string, double> GetRangeWithScoresFromSortedSetByLowestScore(string key, double fromscore, double toscore) { return base.iClient.GetRangeWithScoresFromSortedSetByLowestScore(key, fromscore, toscore); } /// <summary> /// 获取key集合数据,下标从fromRank到分数为toRank的数据 /// </summary> public List<string> GetRangeFromSortedSet(string key, int fromRank, int toRank) { return base.iClient.GetRangeFromSortedSet(key, fromRank, toRank); } /// <summary> /// 获取key集合倒叙排列数据,下标从fromRank到分数为toRank的数据 /// </summary> public List<string> GetRangeFromSortedSetDesc(string key, int fromRank, int toRank) { return base.iClient.GetRangeFromSortedSetDesc(key, fromRank, toRank); } /// <summary> /// 获取key集合数据,下标从fromRank到分数为toRank的数据,带分数 /// </summary> public IDictionary<string, double> GetRangeWithScoresFromSortedSet(string key, int fromRank, int toRank) { return base.iClient.GetRangeWithScoresFromSortedSet(key, fromRank, toRank); } /// <summary> /// 获取key集合倒叙排列数据,下标从fromRank到分数为toRank的数据,带分数 /// </summary> public IDictionary<string, double> GetRangeWithScoresFromSortedSetDesc(string key, int fromRank, int toRank) { return base.iClient.GetRangeWithScoresFromSortedSetDesc(key, fromRank, toRank); } #endregion #region 删除 /// <summary> /// 删除key为value的数据 /// </summary> public bool RemoveItemFromSortedSet(string key, string value) { return base.iClient.RemoveItemFromSortedSet(key, value); } /// <summary> /// 删除下标从minRank到maxRank的key集合数据 /// </summary> public long RemoveRangeFromSortedSet(string key, int minRank, int maxRank) { return base.iClient.RemoveRangeFromSortedSet(key, minRank, maxRank); } /// <summary> /// 删除分数从fromscore到toscore的key集合数据 /// </summary> public long RemoveRangeFromSortedSetByScore(string key, double fromscore, double toscore) { return base.iClient.RemoveRangeFromSortedSetByScore(key, fromscore, toscore); } /// <summary> /// 删除key集合中分数最大的数据 /// </summary> public string PopItemWithHighestScoreFromSortedSet(string key) { return base.iClient.PopItemWithHighestScoreFromSortedSet(key); } /// <summary> /// 删除key集合中分数最小的数据 /// </summary> public string PopItemWithLowestScoreFromSortedSet(string key) { return base.iClient.PopItemWithLowestScoreFromSortedSet(key); } #endregion #region 其它 /// <summary> /// 判断key集合中是否存在value数据 /// </summary> public bool SortedSetContainsItem(string key, string value) { return base.iClient.SortedSetContainsItem(key, value); } /// <summary> /// 为key集合值为value的数据,分数加scoreby,返回相加后的分数 /// </summary> public double IncrementItemInSortedSet(string key, string value, double scoreBy) { return base.iClient.IncrementItemInSortedSet(key, value, scoreBy); } /// <summary> /// 获取keys多个集合的交集,并把交集添加的newkey集合中,返回交集数据的总数 /// </summary> public long StoreIntersectFromSortedSets(string newkey, string[] keys) { return base.iClient.StoreIntersectFromSortedSets(newkey, keys); } /// <summary> /// 获取keys多个集合的并集,并把并集数据添加到newkey集合中,返回并集数据的总数 /// </summary> public long StoreUnionFromSortedSets(string newkey, string[] keys) { return base.iClient.StoreUnionFromSortedSets(newkey, keys); } #endregion }
使用除了排序,其他与Set一样
Console.WriteLine("*****************************************"); { using (RedisZSetService service = new RedisZSetService()) { service.FlushAll();//清理全部数据 service.Add("advanced", "1"); service.Add("advanced", "2"); service.Add("advanced", "5"); service.Add("advanced", "4"); service.Add("advanced", "7"); service.Add("advanced", "5"); service.Add("advanced", "9"); var result1 = service.GetAll("advanced"); var result2 = service.GetAllDesc("advanced"); service.AddItemToSortedSet("Sort", "BY", 123234); service.AddItemToSortedSet("Sort", "走自己的路", 123); service.AddItemToSortedSet("Sort", "redboy", 45); service.AddItemToSortedSet("Sort", "大蛤蟆", 7567); service.AddItemToSortedSet("Sort", "路人甲", 9879); service.AddRangeToSortedSet("Sort", new List<string>() { "123", "花生", "加菲猫" }, 3232); var result3 = service.GetAllWithScoresFromSortedSet("Sort"); //交叉并 } }
排序值、及排序结果
场景(实时排行)
/// <summary> /// 实时排行榜:刷个礼物 /// 维度很多,平台/房间/主播/日/周/月/年 /// A对B 刷个礼物,影响很多 /// 刷礼物只记录流水,不影响排行,凌晨24点跑任务更新 /// /// 实时排行榜 /// Redis-IncrementItemInSortedSet /// 刷礼物时增加redis分数 /// 就可以实时获取最新的排行 /// (多个维度就是多个zSet,刷礼物的时候保存数据库并更新Redis) /// </summary> public class RankManager { private static List<string> UserList = new List<string>() { "Tenk","花生","Ray","阿莫西林","石昊","ywa" }; public static void Show() { using (RedisZSetService service = new RedisZSetService()) { service.FlushAll();//清理全部数据 Task.Run(() => { while (true) { foreach (var user in UserList) { Thread.Sleep(10); service.IncrementItemInSortedSet("陈一发儿", user, new Random().Next(1, 100));//表示在原来刷礼物的基础上增加礼物 } Thread.Sleep(20 * 1000); } }); Task.Run(() => { while (true) { Thread.Sleep(12 * 1000); Console.WriteLine("**********当前排行************"); int i = 1; foreach (var item in service.GetAllWithScoresFromSortedSet("陈一发儿")) { Console.WriteLine($"第{i++}名 {item.Key} 分数{item.Value}"); } //foreach (var item in service.GetAllDesc("陈一发儿")) //{ // Console.WriteLine($"第{i++}名 {item}"); //} } }); Console.Read(); } } }
List
redis 的List类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销, /// Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。 /// </summary> public class RedisListService : RedisBase { #region 赋值 /// <summary> /// 从左侧向list中添加值 /// </summary> public void LPush(string key, string value) { base.iClient.PushItemToList(key, value); } /// <summary> /// 从左侧向list中添加值,并设置过期时间 /// </summary> public void LPush(string key, string value, DateTime dt) { base.iClient.PushItemToList(key, value); base.iClient.ExpireEntryAt(key, dt); } /// <summary> /// 从左侧向list中添加值,设置过期时间 /// </summary> public void LPush(string key, string value, TimeSpan sp) { base.iClient.PushItemToList(key, value); base.iClient.ExpireEntryIn(key, sp); } /// <summary> /// 从右侧向list中添加值 /// </summary> public void RPush(string key, string value) { base.iClient.PrependItemToList(key, value); } /// <summary> /// 从右侧向list中添加值,并设置过期时间 /// </summary> public void RPush(string key, string value, DateTime dt) { base.iClient.PrependItemToList(key, value); base.iClient.ExpireEntryAt(key, dt); } /// <summary> /// 从右侧向list中添加值,并设置过期时间 /// </summary> public void RPush(string key, string value, TimeSpan sp) { base.iClient.PrependItemToList(key, value); base.iClient.ExpireEntryIn(key, sp); } /// <summary> /// 添加key/value /// </summary> public void Add(string key, string value) { base.iClient.AddItemToList(key, value); } /// <summary> /// 添加key/value ,并设置过期时间 /// </summary> public void Add(string key, string value, DateTime dt) { base.iClient.AddItemToList(key, value); base.iClient.ExpireEntryAt(key, dt); } /// <summary> /// 添加key/value。并添加过期时间 /// </summary> public void Add(string key, string value, TimeSpan sp) { base.iClient.AddItemToList(key, value); base.iClient.ExpireEntryIn(key, sp); } /// <summary> /// 为key添加多个值 /// </summary> public void Add(string key, List<string> values) { base.iClient.AddRangeToList(key, values); } /// <summary> /// 为key添加多个值,并设置过期时间 /// </summary> public void Add(string key, List<string> values, DateTime dt) { base.iClient.AddRangeToList(key, values); base.iClient.ExpireEntryAt(key, dt); } /// <summary> /// 为key添加多个值,并设置过期时间 /// </summary> public void Add(string key, List<string> values, TimeSpan sp) { base.iClient.AddRangeToList(key, values); base.iClient.ExpireEntryIn(key, sp); } #endregion #region 获取值 /// <summary> /// 获取list中key包含的数据数量 /// </summary> public long Count(string key) { return base.iClient.GetListCount(key); } /// <summary> /// 获取key包含的所有数据集合 /// </summary> public List<string> Get(string key) { return base.iClient.GetAllItemsFromList(key); } /// <summary> /// 获取key中下标为star到end的值集合 /// </summary> public List<string> Get(string key, int star, int end) { return base.iClient.GetRangeFromList(key, star, end); } #endregion #region 阻塞命令 /// <summary> /// 阻塞命令:从list为key的尾部移除一个值,并返回移除的值,阻塞时间为sp /// </summary> public string BlockingPopItemFromList(string key, TimeSpan? sp) { return base.iClient.BlockingPopItemFromList(key, sp); } /// <summary> /// 阻塞命令:从多个list中尾部移除一个值,并返回移除的值&key,阻塞时间为sp /// </summary> public ItemRef BlockingPopItemFromLists(string[] keys, TimeSpan? sp) { return base.iClient.BlockingPopItemFromLists(keys, sp); } /// <summary> /// 阻塞命令:从list中keys的尾部移除一个值,并返回移除的值,阻塞时间为sp /// </summary> public string BlockingDequeueItemFromList(string key, TimeSpan? sp) { return base.iClient.BlockingDequeueItemFromList(key, sp); } /// <summary> /// 阻塞命令:从多个list中尾部移除一个值,并返回移除的值&key,阻塞时间为sp /// </summary> public ItemRef BlockingDequeueItemFromLists(string[] keys, TimeSpan? sp) { return base.iClient.BlockingDequeueItemFromLists(keys, sp); } /// <summary> /// 阻塞命令:从list中一个fromkey的尾部移除一个值,添加到另外一个tokey的头部,并返回移除的值,阻塞时间为sp /// </summary> public string BlockingPopAndPushItemBetweenLists(string fromkey, string tokey, TimeSpan? sp) { return base.iClient.BlockingPopAndPushItemBetweenLists(fromkey, tokey, sp); } #endregion #region 删除 /// <summary> /// 从尾部移除数据,返回移除的数据 /// </summary> public string PopItemFromList(string key) { var sa = base.iClient.CreateSubscription(); return base.iClient.PopItemFromList(key); } /// <summary> /// 从尾部移除数据,返回移除的数据 /// </summary> public string DequeueItemFromList(string key) { return base.iClient.DequeueItemFromList(key); } /// <summary> /// 移除list中,key/value,与参数相同的值,并返回移除的数量 /// </summary> public long RemoveItemFromList(string key, string value) { return base.iClient.RemoveItemFromList(key, value); } /// <summary> /// 从list的尾部移除一个数据,返回移除的数据 /// </summary> public string RemoveEndFromList(string key) { return base.iClient.RemoveEndFromList(key); } /// <summary> /// 从list的头部移除一个数据,返回移除的值 /// </summary> public string RemoveStartFromList(string key) { return base.iClient.RemoveStartFromList(key); } #endregion #region 其它 /// <summary> /// 从一个list的尾部移除一个数据,添加到另外一个list的头部,并返回移动的值 /// </summary> public string PopAndPushItemBetweenLists(string fromKey, string toKey) { return base.iClient.PopAndPushItemBetweenLists(fromKey, toKey); } public void TrimList(string key, int start, int end) { base.iClient.TrimList(key, start, end); } #endregion #region 发布订阅 public void Publish(string channel, string message) { base.iClient.PublishMessage(channel, message); } public void Subscribe(string channel, Action<string, string, IRedisSubscription> actionOnMessage) { var subscription = base.iClient.CreateSubscription(); subscription.OnSubscribe = c => { Console.WriteLine($"订阅频道{c}"); Console.WriteLine(); }; //取消订阅 subscription.OnUnSubscribe = c => { Console.WriteLine($"取消订阅 {c}"); Console.WriteLine(); }; subscription.OnMessage += (c, s) => { actionOnMessage(c, s, subscription); }; Console.WriteLine($"开始启动监听 {channel}"); subscription.SubscribeToChannels(channel); //blocking } public void UnSubscribeFromChannels(string channel) { var subscription = base.iClient.CreateSubscription(); subscription.UnSubscribeFromChannels(channel); } #endregion }
使用
Console.WriteLine("*****************************************"); { using (RedisListService service = new RedisListService()) { service.FlushAll(); service.Add("article", "eleven1234"); service.Add("article", "kevin"); service.Add("article", "大叔"); service.Add("article", "C卡"); service.Add("article", "触不到的线"); service.Add("article", "程序错误"); var result1 = service.Get("article"); var result2 = service.Get("article", 0, 3); }
后进先出(栈的效果)
service.FlushAll(); service.Add("article", "eleven1234"); service.Add("article", "kevin"); service.Add("article", "大叔"); service.Add("article", "C卡"); service.Add("article", "触不到的线"); service.Add("article", "程序错误"); for (int i = 0; i < 5; i++) { Console.WriteLine(service.PopItemFromList("article")); var result1 = service.Get("article"); }
i=0 时
i=1时
i=2时
先进先出(队列的效果)
// 队列:生产者消费者模型 service.FlushAll(); service.RPush("article", "eleven1234"); service.RPush("article", "kevin"); service.RPush("article", "大叔"); service.RPush("article", "C卡"); service.RPush("article", "触不到的线"); service.RPush("article", "程序错误"); for (int i = 0; i < 5; i++) { Console.WriteLine(service.PopItemFromList("article")); var result1 = service.Get("article"); } //分布式缓存,多服务器都可以访问到,多个生产者,多个消费者,任何产品只被消费一次
i=0时
i=1时
i=2时
生产者
using (RedisListService service = new RedisListService()) { List<string> stringList = new List<string>(); for (int i = 0; i < 10; i++) { stringList.Add(string.Format($"放入任务{i}")); } service.Add("test", "这是一个学生Add1"); service.Add("test", "这是一个学生Add2"); service.Add("test", "这是一个学生Add3"); service.LPush("test", "这是一个学生LPush1"); service.LPush("test", "这是一个学生LPush2"); service.LPush("test", "这是一个学生LPush3"); service.LPush("test", "这是一个学生LPush4"); service.LPush("test", "这是一个学生LPush5"); service.LPush("test", "这是一个学生LPush6"); service.RPush("test", "这是一个学生RPush1"); service.RPush("test", "这是一个学生RPush2"); service.RPush("test", "这是一个学生RPush3"); service.RPush("test", "这是一个学生RPush4"); service.RPush("test", "这是一个学生RPush5"); service.RPush("test", "这是一个学生RPush6"); service.Add("task", stringList); Console.WriteLine(service.Count("test")); Console.WriteLine(service.Count("task")); var list = service.Get("test"); list = service.Get("task", 2, 4); Action act = new Action(() => { while (true) { Console.WriteLine("************请输入数据**************"); string testTask = Console.ReadLine(); service.LPush("test", testTask); } }); act.EndInvoke(act.BeginInvoke(null, null)); }
消费者
public class ServiceStackProcessor { public static void Show() { string path = AppDomain.CurrentDomain.BaseDirectory; string tag = path.Split('/', '\').Last(s => !string.IsNullOrEmpty(s)); Console.WriteLine($"这里是 {tag} 启动了。。"); using (RedisListService service = new RedisListService()) { Action act = new Action(() => { while (true) { var result = service.BlockingPopItemFromLists(new string[] { "test", "task" }, TimeSpan.FromHours(3)); Thread.Sleep(100); Console.WriteLine($"这里是 {tag} 队列获取的消息 {result.Id} {result.Item}"); } }); act.EndInvoke(act.BeginInvoke(null, null)); } } }
可以 一个生产者对应多个消费者,也可以一个消费者对应多个生产者,多对多也可以
下面是 一个生产者对应多个消费者的效果图
发布订阅
发布订阅:观察者,一个数据源,多个接受者,只要订阅了就可以收到的,能被多个数据源共享
#region 发布订阅:观察者,一个数据源,多个接受者,只要订阅了就可以收到的,能被多个数据源共享 Task.Run(() => { using (RedisListService service = new RedisListService()) { //订阅频道 service.Subscribe("Eleven", (c, message, iRedisSubscription) => { Console.WriteLine($"注册{1}{c}:{message},Dosomething else"); if (message.Equals("exit")) iRedisSubscription.UnSubscribeFromChannels("Eleven");//取消订阅频道 });//blocking } }); Task.Run(() => { using (RedisListService service = new RedisListService()) { //订阅频道 service.Subscribe("Eleven", (c, message, iRedisSubscription) => { Console.WriteLine($"注册{2}{c}:{message},Dosomething else"); if (message.Equals("exit")) iRedisSubscription.UnSubscribeFromChannels("Eleven");//取消订阅频道 });//blocking } }); Task.Run(() => { using (RedisListService service = new RedisListService()) { //订阅频道 service.Subscribe("Twelve", (c, message, iRedisSubscription) => { Console.WriteLine($"注册{3}{c}:{message},Dosomething else"); if (message.Equals("exit")) iRedisSubscription.UnSubscribeFromChannels("Twelve");//取消订阅频道 });//blocking } }); using (RedisListService service = new RedisListService()) { Thread.Sleep(1000); //频道发布消息 service.Publish("Eleven", "Eleven123"); service.Publish("Eleven", "Eleven234"); service.Publish("Eleven", "Eleven345"); service.Publish("Eleven", "Eleven456"); //频道发布消息 service.Publish("Twelve", "Twelve123"); service.Publish("Twelve", "Twelve234"); service.Publish("Twelve", "Twelve345"); service.Publish("Twelve", "Twelve456"); Console.WriteLine("**********************************************"); //频道发布 封号退出消息 service.Publish("Eleven", "exit"); service.Publish("Eleven", "123Eleven"); service.Publish("Eleven", "234Eleven"); service.Publish("Eleven", "345Eleven"); service.Publish("Eleven", "456Eleven"); //频道发布 封号退出消息 service.Publish("Twelve", "exit"); service.Publish("Twelve", "123Twelve"); service.Publish("Twelve", "234Twelve"); service.Publish("Twelve", "345Twelve"); service.Publish("Twelve", "456Twelve"); } #endregion
-----------------------------------------------------------------------------------------------------------------
StackExchange.Redis
下面额代码类均是通过 StackExchange.Redis 来对Redis进行各种操作
Redis操作方法基础类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Redis操作方法基础类 /// </summary> public abstract class RedisBase : IDisposable { #region 属性字段 /// <summary> /// 网站Redis 系统自定义Key前缀 /// </summary> protected string CustomKey = RedisManager.RedisSysCustomKey; /// <summary> /// 网站Redis 链接字符串 /// </summary> protected readonly ConnectionMultiplexer _conn; /// <summary> /// Redis操作对象 /// </summary> protected readonly IDatabase redis = null; #endregion #region 构造函数 /// <summary> /// 初始化Redis操作方法基础类 /// </summary> /// <param name="dbNum">操作的数据库索引0-64(需要在conf文件中配置)</param> protected RedisBase(int? dbNum = null) { _conn = RedisManager.Instance; if (_conn != null) { redis = _conn.GetDatabase(dbNum ?? RedisManager.RedisDataBaseIndex); } else { throw new ArgumentNullException("Redis连接初始化失败"); } } private bool _disposed = false; protected virtual void Dispose(bool disposing) { if (!this._disposed) { if (disposing) { _conn.Dispose(); } } this._disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion 构造函数 #region 外部调用静态方法 /// <summary> /// 获取Redis的String数据类型操作辅助方法类 /// </summary> /// <returns></returns> public static RedisStringService StringService => new RedisStringService(); /// <summary> /// 获取Redis的Hash数据类型操作辅助方法类 /// </summary> /// <returns></returns> public static RedisHashService HashService => new RedisHashService(); /// <summary> /// 获取Redis的List数据类型操作辅助方法类 /// </summary> /// <returns></returns> public static RedisListService ListService => new RedisListService(); /// <summary> /// 获取Redis的Set无序集合数据类型操作辅助方法类 /// </summary> /// <returns></returns> public static RedisSetService SetService => new RedisSetService(); /// <summary> /// 获取Redis的SortedSet(ZSet)有序集合数据类型操作辅助方法类 /// </summary> /// <returns></returns> public static RedisSortedSetService SortedSetService => new RedisSortedSetService(); #endregion #region 公共操作方法 #region 不建议公开这些方法,如果项目中用不到,建议注释或者删除 /// <summary> /// 获取Redis事务对象 /// </summary> /// <returns></returns> public ITransaction CreateTransaction() => redis.CreateTransaction(); /// <summary> /// 获取Redis服务和常用操作对象 /// </summary> /// <returns></returns> public IDatabase GetDatabase() => redis; /// <summary> /// 获取Redis服务 /// </summary> /// <param name="hostAndPort"></param> /// <returns></returns> public IServer GetServer(string hostAndPort) => _conn.GetServer(hostAndPort); /// <summary> /// 执行Redis事务 /// </summary> /// <param name="act"></param> /// <returns></returns> public bool RedisTransaction(Action<ITransaction> act) { var tran = redis.CreateTransaction(); act.Invoke(tran); bool committed = tran.Execute(); return committed; } /// <summary> /// Redis锁 /// </summary> /// <param name="act"></param> /// <param name="ts">锁住时间</param> public void RedisLockTake(Action act, TimeSpan ts) { RedisValue token = Environment.MachineName; string lockKey = "lock_LockTake"; if (redis.LockTake(lockKey, token, ts)) { try { act(); } finally { redis.LockRelease(lockKey, token); } } } #endregion 其他 #region 常用Key操作 /// <summary> /// 设置前缀 /// </summary> /// <param name="customKey"></param> public void SetSysCustomKey(string customKey) => CustomKey = customKey; /// <summary> /// 组合缓存Key名称 /// </summary> /// <param name="oldKey"></param> /// <returns></returns> public string AddSysCustomKey(string oldKey) => $"{CustomKey}_{oldKey}"; #region 同步方法 /// <summary> /// 删除单个key /// </summary> /// <param name="key">要删除的key</param> /// <returns>是否删除成功</returns> public bool KeyDelete(string key) { key = AddSysCustomKey(key); return redis.KeyDelete(key); } /// <summary> /// 删除多个key /// </summary> /// <param name="keys">要删除的key集合</param> /// <returns>成功删除的个数</returns> public long KeyDelete(params string[] keys) { RedisKey[] newKeys = keys.Select(o => (RedisKey)AddSysCustomKey(o)).ToArray(); return redis.KeyDelete(newKeys); } /// <summary> /// 清空当前DataBase中所有Key /// </summary> public void KeyFulsh() { //直接执行清除命令 redis.Execute("FLUSHDB"); } /// <summary> /// 判断key是否存在 /// </summary> /// <param name="key">要判断的key</param> /// <returns></returns> public bool KeyExists(string key) { key = AddSysCustomKey(key); return redis.KeyExists(key); } /// <summary> /// 重新命名key /// </summary> /// <param name="key">就的redis key</param> /// <param name="newKey">新的redis key</param> /// <returns></returns> public bool KeyRename(string key, string newKey) { key = AddSysCustomKey(key); newKey = AddSysCustomKey(newKey); return redis.KeyRename(key, newKey); } /// <summary> /// 设置Key的过期时间 /// </summary> /// <param name="key">redis key</param> /// <param name="expiry">过期时间</param> /// <returns></returns> public bool KeyExpire(string key, TimeSpan? expiry = default(TimeSpan?)) { key = AddSysCustomKey(key); return redis.KeyExpire(key, expiry); } #endregion #region 异步方法 /// <summary> /// 删除单个key /// </summary> /// <param name="key">要删除的key</param> /// <returns>是否删除成功</returns> public async Task<bool> KeyDeleteAsync(string key) { key = AddSysCustomKey(key); return await redis.KeyDeleteAsync(key); } /// <summary> /// 删除多个key /// </summary> /// <param name="keys">要删除的key集合</param> /// <returns>成功删除的个数</returns> public async Task<long> KeyDeleteAsync(params string[] keys) { RedisKey[] newKeys = keys.Select(o => (RedisKey)AddSysCustomKey(o)).ToArray(); return await redis.KeyDeleteAsync(newKeys); } /// <summary> /// 清空当前DataBase中所有Key /// </summary> public async Task KeyFulshAsync() { //直接执行清除命令 await redis.ExecuteAsync("FLUSHDB"); } /// <summary> /// 判断key是否存在 /// </summary> /// <param name="key">要判断的key</param> /// <returns></returns> public async Task<bool> KeyExistsAsync(string key) { key = AddSysCustomKey(key); return await redis.KeyExistsAsync(key); } /// <summary> /// 重新命名key /// </summary> /// <param name="key">就的redis key</param> /// <param name="newKey">新的redis key</param> /// <returns></returns> public async Task<bool> KeyRenameAsync(string key, string newKey) { key = AddSysCustomKey(key); newKey = AddSysCustomKey(newKey); return await redis.KeyRenameAsync(key, newKey); } /// <summary> /// 设置Key的过期时间 /// </summary> /// <param name="key">redis key</param> /// <param name="expiry">过期时间</param> /// <returns></returns> public async Task<bool> KeyExpireAsync(string key, TimeSpan? expiry = default(TimeSpan?)) { key = AddSysCustomKey(key); return await redis.KeyExpireAsync(key, expiry); } #endregion #endregion #endregion #region 辅助方法 /// <summary> /// 将对象转换成string字符串 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="value"></param> /// <returns></returns> protected string ConvertJson<T>(T value) { string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value, Formatting.None); return result; } /// <summary> /// 将值反系列化成对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="value"></param> /// <returns></returns> protected T ConvertObj<T>(RedisValue value) { return value.IsNullOrEmpty ? default(T) : JsonConvert.DeserializeObject<T>(value); } /// <summary> /// 将值反系列化成对象集合 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="values"></param> /// <returns></returns> protected List<T> ConvetList<T>(RedisValue[] values) { List<T> result = new List<T>(); foreach (var item in values) { var model = ConvertObj<T>(item); result.Add(model); } return result; } /// <summary> /// 将string类型的Key转换成 <see cref="RedisKey"/> 型的Key /// </summary> /// <param name="redisKeys"></param> /// <returns></returns> protected RedisKey[] ConvertRedisKeys(List<string> redisKeys) => redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray(); /// <summary> /// 将string类型的Key转换成 <see cref="RedisKey"/> 型的Key /// </summary> /// <param name="redisKeys"></param> /// <returns></returns> protected RedisKey[] ConvertRedisKeys(params string[] redisKeys) => redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray(); /// <summary> /// 将string类型的Key转换成 <see cref="RedisKey"/> 型的Key,并添加前缀字符串 /// </summary> /// <param name="redisKeys"></param> /// <returns></returns> protected RedisKey[] ConvertRedisKeysAddSysCustomKey(params string[] redisKeys) => redisKeys.Select(redisKey => (RedisKey)AddSysCustomKey(redisKey)).ToArray(); /// <summary> /// 将值集合转换成RedisValue集合 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="redisValues"></param> /// <returns></returns> protected RedisValue[] ConvertRedisValue<T>(params T[] redisValues) => redisValues.Select(o => (RedisValue)ConvertJson<T>(o)).ToArray(); #endregion 辅助方法 }
Redis基本信息初始化辅助类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Redis基本信息初始化辅助类 /// </summary> internal class RedisManager { //private static LogHelper log = LogHelper.LogInterface<RedisManager>(); private static readonly object Locker = new object(); private static ConnectionMultiplexer _instance; private static readonly ConcurrentDictionary<string, ConnectionMultiplexer> ConnectionCache = new ConcurrentDictionary<string, ConnectionMultiplexer>(); /// <summary> /// Redis保存的Key前缀,会自动添加到指定的Key名称前 /// </summary> internal static readonly string RedisSysCustomKey = ConfigurationManager.AppSettings["RedisSysCustomKey"]; /// <summary> /// 当前连接的Redis中的DataBase索引,默认0-16,可以在service.conf配置,最高64 /// </summary> internal static readonly int RedisDataBaseIndex = int.Parse(ConfigurationManager.AppSettings["RedisDataBaseIndex"]); /// <summary> /// 当前连接的Redis中连接字符串,格式为:127.0.0.1:6379,allowadmin=true,passowrd=pwd /// </summary> internal static readonly string RedisHostConnection = ConfigurationManager.AppSettings["RedisHostConnection"]; /// <summary> /// 单例获取 /// </summary> public static ConnectionMultiplexer Instance { get { if (_instance == null) { lock (Locker) { if (_instance == null || !_instance.IsConnected) { _instance = GetManager(); } } } return _instance; } } /// <summary> /// 缓存获取 /// </summary> /// <param name="connectionString"></param> /// <returns></returns> public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString) { if (!ConnectionCache.ContainsKey(connectionString)) { ConnectionCache[connectionString] = GetManager(connectionString); } return ConnectionCache[connectionString]; } /// <summary> /// 内部方法,获取Redis连接 /// </summary> /// <param name="connectionString"></param> /// <returns></returns> private static ConnectionMultiplexer GetManager(string connectionString = null) { connectionString = connectionString ?? RedisHostConnection; var connect = ConnectionMultiplexer.Connect(connectionString); //注册如下事件 connect.ConnectionFailed += MuxerConnectionFailed; connect.ConnectionRestored += MuxerConnectionRestored; connect.ErrorMessage += MuxerErrorMessage; connect.ConfigurationChanged += MuxerConfigurationChanged; connect.HashSlotMoved += MuxerHashSlotMoved; connect.InternalError += MuxerInternalError; return connect; } #region 事件 /// <summary> /// 配置更改时 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e) { //log.InfoAsync($"Configuration changed: {e.EndPoint}"); } /// <summary> /// 发生错误时 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e) { //log.InfoAsync($"ErrorMessage: {e.Message}"); } /// <summary> /// 重新建立连接之前的错误 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e) { //log.InfoAsync($"ConnectionRestored: {e.EndPoint}"); } /// <summary> /// 连接失败 , 如果重新连接成功你将不会收到这个通知 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e) { //log.InfoAsync($"重新连接:Endpoint failed: {e.EndPoint}, {e.FailureType} , {(e.Exception == null ? "" : e.Exception.Message)}"); } /// <summary> /// 更改集群 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e) { //log.InfoAsync($"HashSlotMoved:NewEndPoint{e.NewEndPoint}, OldEndPoint{e.OldEndPoint}"); } /// <summary> /// redis类库错误 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void MuxerInternalError(object sender, InternalErrorEventArgs e) { //log.InfoAsync($"InternalError:Message{ e.Exception.Message}"); } #endregion 事件 }
String
redis 的string类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// key-value 键值对:value可以是序列化的数据 /// </summary> public class RedisStringService : RedisBase { #region 构造函数 /// <summary> /// 初始化Redis的String数据结构操作 /// </summary> /// <param name="dbNum">操作的数据库索引0-64(需要在conf文件中配置)</param> public RedisStringService(int? dbNum = null) : base(dbNum) { } #endregion #region 同步方法 /// <summary> /// 添加单个key value /// </summary> /// <param name="key">Redis Key</param> /// <param name="value">保存的值</param> /// <param name="expiry">过期时间</param> /// <returns></returns> public bool StringSet(string key, string value, TimeSpan? expiry = default(TimeSpan?)) { key = AddSysCustomKey(key); return base.redis.StringSet(key, value, expiry); } /// <summary> /// 添加多个key/value /// </summary> /// <param name="valueList">key/value集合</param> /// <returns></returns> public bool StringSet(Dictionary<string, string> valueList) { var newkeyValues = valueList.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToArray(); return base.redis.StringSet(newkeyValues); } /// <summary> /// 保存一个对象 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="key">保存的Key名称</param> /// <param name="value">对象实体</param> /// <param name="expiry">过期时间</param> /// <returns></returns> public bool StringSet<T>(string key, T value, TimeSpan? expiry = default(TimeSpan?)) { key = AddSysCustomKey(key); string jsonValue = ConvertJson(value); return base.redis.StringSet(key, jsonValue, expiry); } /// <summary> /// 在原有key的value值之后追加value /// </summary> /// <param name="key">追加的Key名称</param> /// <param name="value">追加的值</param> /// <returns></returns> public long StringAppend(string key, string value) { key = AddSysCustomKey(key); return base.redis.StringAppend(key, value); } /// <summary> /// 获取单个key的值 /// </summary> /// <param name="key">要读取的Key名称</param> /// <returns></returns> public string StringGet(string key) { key = AddSysCustomKey(key); return base.redis.StringGet(key); } /// <summary> /// 获取多个key的value值 /// </summary> /// <param name="keys">要获取值的Key集合</param> /// <returns></returns> public List<string> StringGet(params string[] keys) { var newKeys = ConvertRedisKeysAddSysCustomKey(keys); var values = base.redis.StringGet(newKeys); return values.Select(o => o.ToString()).ToList(); } /// <summary> /// 获取单个key的value值 /// </summary> /// <typeparam name="T">返回数据类型</typeparam> /// <param name="key">要获取值的Key集合</param> /// <returns></returns> public T StringGet<T>(string key) { key = AddSysCustomKey(key); var values = base.redis.StringGet(key); return ConvertObj<T>(values); } /// <summary> /// 获取多个key的value值 /// </summary> /// <typeparam name="T">返回数据类型</typeparam> /// <param name="keys">要获取值的Key集合</param> /// <returns></returns> public List<T> StringGet<T>(params string[] keys) { var newKeys = ConvertRedisKeysAddSysCustomKey(keys); var values = base.redis.StringGet(newKeys); return ConvetList<T>(values); } /// <summary> /// 获取旧值赋上新值 /// </summary> /// <param name="key">Key名称</param> /// <param name="value">新值</param> /// <returns></returns> public string StringGetSet(string key, string value) { key = AddSysCustomKey(key); return base.redis.StringGetSet(key, value); } /// <summary> /// 获取旧值赋上新值 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="key">Key名称</param> /// <param name="value">新值</param> /// <returns></returns> public T StringGetSet<T>(string key, T value) { key = AddSysCustomKey(key); string jsonValue = ConvertJson(value); var oValue = base.redis.StringGetSet(key, jsonValue); return ConvertObj<T>(oValue); } /// <summary> /// 获取值的长度 /// </summary> /// <param name="key">Key名称</param> /// <returns></returns> public long StringGetLength(string key) { key = AddSysCustomKey(key); return base.redis.StringLength(key); } /// <summary> /// 数字增长val,返回自增后的值 /// </summary> /// <param name="key"></param> /// <param name="val">可以为负</param> /// <returns>增长后的值</returns> public double StringIncrement(string key, double val = 1) { key = AddSysCustomKey(key); return base.redis.StringIncrement(key, val); } /// <summary> /// 数字减少val,返回自减少的值 /// </summary> /// <param name="key"></param> /// <param name="val">可以为负</param> /// <returns>减少后的值</returns> public double StringDecrement(string key, double val = 1) { key = AddSysCustomKey(key); return base.redis.StringDecrement(key, val); } #endregion #region 异步方法 /// <summary> /// 异步方法 保存单个key value /// </summary> /// <param name="key">Redis Key</param> /// <param name="value">保存的值</param> /// <param name="expiry">过期时间</param> /// <returns></returns> public async Task<bool> StringSetAsync(string key, string value, TimeSpan? expiry = default(TimeSpan?)) { key = AddSysCustomKey(key); return await base.redis.StringSetAsync(key, value, expiry); } /// <summary> /// 异步方法 添加多个key/value /// </summary> /// <param name="valueList">key/value集合</param> /// <returns></returns> public async Task<bool> StringSetAsync(Dictionary<string, string> valueList) { var newkeyValues = valueList.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToArray(); return await base.redis.StringSetAsync(newkeyValues); } /// <summary> /// 异步方法 保存一个对象 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="key">保存的Key名称</param> /// <param name="obj">对象实体</param> /// <param name="expiry">过期时间</param> /// <returns></returns> public async Task<bool> StringSetAsync<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) { key = AddSysCustomKey(key); string jsonValue = ConvertJson(obj); return await base.redis.StringSetAsync(key, jsonValue, expiry); } /// <summary> /// 异步方法 在原有key的value值之后追加value /// </summary> /// <param name="key">追加的Key名称</param> /// <param name="value">追加的值</param> /// <returns></returns> public async Task<long> StringAppendAsync(string key, string value) { key = AddSysCustomKey(key); return await base.redis.StringAppendAsync(key, value); } /// <summary> /// 异步方法 获取单个key的值 /// </summary> /// <param name="key">要读取的Key名称</param> /// <returns></returns> public async Task<string> StringGetAsync(string key) { key = AddSysCustomKey(key); return await base.redis.StringGetAsync(key); } /// <summary> /// 异步方法 获取多个key的value值 /// </summary> /// <param name="keys">要获取值的Key集合</param> /// <returns></returns> public async Task<List<string>> StringGetAsync(params string[] keys) { var newKeys = ConvertRedisKeysAddSysCustomKey(keys); var values = await base.redis.StringGetAsync(newKeys); return values.Select(o => o.ToString()).ToList(); } /// <summary> /// 异步方法 获取单个key的value值 /// </summary> /// <typeparam name="T">返回数据类型</typeparam> /// <param name="key">要获取值的Key集合</param> /// <returns></returns> public async Task<T> StringGetAsync<T>(string key) { key = AddSysCustomKey(key); var values = await base.redis.StringGetAsync(key); return ConvertObj<T>(values); } /// <summary> /// 异步方法 获取多个key的value值 /// </summary> /// <typeparam name="T">返回数据类型</typeparam> /// <param name="keys">要获取值的Key集合</param> /// <returns></returns> public async Task<List<T>> StringGetAsync<T>(params string[] keys) { var newKeys = ConvertRedisKeysAddSysCustomKey(keys); var values = await base.redis.StringGetAsync(newKeys); return ConvetList<T>(values); } /// <summary> /// 异步方法 获取旧值赋上新值 /// </summary> /// <param name="key">Key名称</param> /// <param name="value">新值</param> /// <returns></returns> public async Task<string> StringGetSetAsync(string key, string value) { key = AddSysCustomKey(key); return await base.redis.StringGetSetAsync(key, value); } /// <summary> /// 异步方法 获取旧值赋上新值 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="key">Key名称</param> /// <param name="value">新值</param> /// <returns></returns> public async Task<T> StringGetSetAsync<T>(string key, T value) { key = AddSysCustomKey(key); string jsonValue = ConvertJson(value); var oValue = await base.redis.StringGetSetAsync(key, jsonValue); return ConvertObj<T>(oValue); } /// <summary> /// 异步方法 获取值的长度 /// </summary> /// <param name="key">Key名称</param> /// <returns></returns> public async Task<long> StringGetLengthAsync(string key) { key = AddSysCustomKey(key); return await base.redis.StringLengthAsync(key); } /// <summary> /// 异步方法 数字增长val,返回自增后的值 /// </summary> /// <param name="key"></param> /// <param name="val">可以为负</param> /// <returns>增长后的值</returns> public async Task<double> StringIncrementAsync(string key, double val = 1) { key = AddSysCustomKey(key); return await base.redis.StringIncrementAsync(key, val); } /// <summary> /// 异步方法 数字减少val,返回自减少的值 /// </summary> /// <param name="key"></param> /// <param name="val">可以为负</param> /// <returns>减少后的值</returns> public async Task<double> StringDecrementAsync(string key, double val = 1) { key = AddSysCustomKey(key); return await base.redis.StringDecrementAsync(key, val); } #endregion }
使用
Console.WriteLine("*****************************************"); { //key value 都是string 假如是个对象呢?序列化一下 //假如要修改某一个属性的值 读--反序列化--修改--序列化 memcached using (RedisStringService service = new RedisStringService()) { service.KeyFulsh(); service.StringSet("RedisStringService_key1", "RedisStringService_value1"); Console.WriteLine(service.StringGet("RedisStringService_key1")); Console.WriteLine(service.StringGetSet("RedisStringService_key1", "RedisStringService_value2")); Console.WriteLine(service.StringGet("RedisStringService_key1")); service.StringAppend("RedisStringService_key1", "Append"); Console.WriteLine(service.StringGet("RedisStringService_key1")); service.StringSet("RedisStringService_key1", "RedisStringService_value", new TimeSpan(0, 0, 0, 5)); Console.WriteLine(service.StringGet("RedisStringService_key1")); Thread.Sleep(5000); Console.WriteLine(service.StringGet("RedisStringService_key1")); } }
Hashtable
redis 的Hash类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Hash:类似dictionary,通过索引快速定位到指定元素的,耗时均等,跟string的区别在于不用反序列化,直接修改某个字段 /// string的话要么是 001:序列化整个实体 /// 要么是 001_name: 001_pwd: 多个key-value /// Hash的话,一个hashid-{key:value;key:value;key:value;} /// 可以一次性查找实体,也可以单个,还可以单个修改 /// </summary> public class RedisHashService : RedisBase { #region 构造函数 /// <summary> /// 初始化Redis的Hash数据结构操作 /// </summary> /// <param name="dbNum">操作的数据库索引0-64(需要在conf文件中配置)</param> public RedisHashService(int? dbNum = null) : base(dbNum) { } #endregion #region 同步方法 /// <summary> /// 判断某个数据是否已经被缓存 /// </summary> /// <param name="key"></param> /// <param name="dataKey"></param> /// <returns></returns> public bool HashExists(string key, string dataKey) { key = AddSysCustomKey(key); return base.redis.HashExists(key, dataKey); } /// <summary> /// 存储数据到hash表 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="dataKey"></param> /// <param name="t"></param> /// <returns></returns> public bool HashSet<T>(string key, string dataKey, T t) { key = AddSysCustomKey(key); string json = ConvertJson(t); return base.redis.HashSet(key, dataKey, json); } /// <summary> /// 移除hash中的某值 /// </summary> /// <param name="key"></param> /// <param name="dataKey"></param> /// <returns></returns> public bool HashDelete(string key, string dataKey) { key = AddSysCustomKey(key); return base.redis.HashDelete(key, dataKey); } /// <summary> /// 移除hash中的多个值 /// </summary> /// <param name="key"></param> /// <param name="dataKeys"></param> /// <returns></returns> public long HashDelete(string key, params string[] dataKeys) { key = AddSysCustomKey(key); var newValues = dataKeys.Select(o => (RedisValue)o).ToArray(); return base.redis.HashDelete(key, newValues); } /// <summary> /// 从hash表获取数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="dataKey"></param> /// <returns></returns> public T HashGet<T>(string key, string dataKey) { key = AddSysCustomKey(key); string value = base.redis.HashGet(key, dataKey); return ConvertObj<T>(value); } /// <summary> /// 数字增长val,返回自增后的值 /// </summary> /// <param name="key"></param> /// <param name="dataKey"></param> /// <param name="val">可以为负</param> /// <returns>增长后的值</returns> public double HashIncrement(string key, string dataKey, double val = 1) { key = AddSysCustomKey(key); return base.redis.HashIncrement(key, dataKey, val); } /// <summary> /// 数字减少val,返回自减少的值 /// </summary> /// <param name="key"></param> /// <param name="dataKey"></param> /// <param name="val">可以为负</param> /// <returns>减少后的值</returns> public double HashDecrement(string key, string dataKey, double val = 1) { key = AddSysCustomKey(key); return base.redis.HashDecrement(key, dataKey, val); } /// <summary> /// 获取hashkey所有key名称 /// </summary> /// <param name="key"></param> /// <returns></returns> public string[] HashKeys(string key) { key = AddSysCustomKey(key); RedisValue[] values = base.redis.HashKeys(key); return values.Select(o=>o.ToString()).ToArray(); } /// <summary> /// 获取hashkey所有key与值,必须保证Key内的所有数据类型一致 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public Dictionary<string, T> HashGetAll<T>(string key) { key = AddSysCustomKey(key); var query = base.redis.HashGetAll(key); Dictionary<string, T> dic = new Dictionary<string, T>(); foreach (var item in query) { dic.Add(item.Name, ConvertObj<T>(item.Value)); } return dic; } #endregion 同步方法 #region 异步方法 /// <summary> /// 异步方法 判断某个数据是否已经被缓存 /// </summary> /// <param name="key"></param> /// <param name="dataKey"></param> /// <returns></returns> public async Task<bool> HashExistsAsync(string key, string dataKey) { key = AddSysCustomKey(key); return await base.redis.HashExistsAsync(key, dataKey); } /// <summary> /// 异步方法 存储数据到hash表 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="dataKey"></param> /// <param name="t"></param> /// <returns></returns> public async Task<bool> HashSetAsync<T>(string key, string dataKey, T t) { key = AddSysCustomKey(key); string json = ConvertJson(t); return await base.redis.HashSetAsync(key, dataKey, json); } /// <summary> /// 异步方法 移除hash中的某值 /// </summary> /// <param name="key"></param> /// <param name="dataKey"></param> /// <returns></returns> public async Task<bool> HashDeleteAsync(string key, string dataKey) { key = AddSysCustomKey(key); return await base.redis.HashDeleteAsync(key, dataKey); } /// <summary> /// 异步方法 移除hash中的多个值 /// </summary> /// <param name="key"></param> /// <param name="dataKeys"></param> /// <returns></returns> public async Task<long> HashDeleteAsync(string key, params string[] dataKeys) { key = AddSysCustomKey(key); var newValues = dataKeys.Select(o => (RedisValue)o).ToArray(); return await base.redis.HashDeleteAsync(key, newValues); } /// <summary> /// 异步方法 从hash表获取数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="dataKey"></param> /// <returns></returns> public async Task<T> HashGetAsync<T>(string key, string dataKey) { key = AddSysCustomKey(key); string value = await base.redis.HashGetAsync(key, dataKey); return ConvertObj<T>(value); } /// <summary> /// 异步方法 数字增长val,返回自增后的值 /// </summary> /// <param name="key"></param> /// <param name="dataKey"></param> /// <param name="val">可以为负</param> /// <returns>增长后的值</returns> public async Task<double> HashIncrementAsync(string key, string dataKey, double val = 1) { key = AddSysCustomKey(key); return await base.redis.HashIncrementAsync(key, dataKey, val); } /// <summary> /// 异步方法 数字减少val,返回自减少的值 /// </summary> /// <param name="key"></param> /// <param name="dataKey"></param> /// <param name="val">可以为负</param> /// <returns>减少后的值</returns> public async Task<double> HashDecrementAsync(string key, string dataKey, double val = 1) { key = AddSysCustomKey(key); return await base.redis.HashDecrementAsync(key, dataKey, val); } /// <summary> /// 异步方法 获取hashkey所有key名称 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<string[]> HashKeysAsync(string key) { key = AddSysCustomKey(key); RedisValue[] values = await base.redis.HashKeysAsync(key); return values.Select(o => o.ToString()).ToArray(); } /// <summary> /// 获取hashkey所有key与值,必须保证Key内的所有数据类型一致 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public async Task<Dictionary<string, T>> HashGetAllAsync<T>(string key) { key = AddSysCustomKey(key); var query = await base.redis.HashGetAllAsync(key); Dictionary<string, T> dic = new Dictionary<string, T>(); foreach (var item in query) { dic.Add(item.Name, ConvertObj<T>(item.Value)); } return dic; } #endregion 异步方法 }
Set
redis 的Set类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Set:用哈希表来保持字符串的唯一性,没有先后顺序,存储一些集合性的数据 /// 1.共同好友、二度好友 /// 2.利用唯一性,可以统计访问网站的所有独立 IP /// </summary> public class RedisSetService : RedisBase { #region 构造函数 /// <summary> /// 初始化Redis的Set无序数据结构操作 /// </summary> /// <param name="dbNum">操作的数据库索引0-64(需要在conf文件中配置)</param> public RedisSetService(int? dbNum = null) : base(dbNum) { } #endregion #region 同步方法 /// <summary> /// 在Key集合中添加一个value值 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="key">Key名称</param> /// <param name="value">值</param> /// <returns></returns> public bool SetAdd<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return base.redis.SetAdd(key, jValue); } /// <summary> /// 在Key集合中添加多个value值 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="key">Key名称</param> /// <param name="value">值列表</param> /// <returns></returns> public long SetAdd<T>(string key, List<T> value) { key = AddSysCustomKey(key); RedisValue[] valueList = base.ConvertRedisValue(value.ToArray()); return base.redis.SetAdd(key, valueList); } /// <summary> /// 获取key集合值的数量 /// </summary> /// <param name="key"></param> /// <returns></returns> public long SetLength(string key) { key = AddSysCustomKey(key); return base.redis.SetLength(key); } /// <summary> /// 判断Key集合中是否包含指定的值 /// </summary> /// <typeparam name="T">值类型</typeparam> /// <param name="key"></param> /// <param name="value">要判断是值</param> /// <returns></returns> public bool SetContains<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return base.redis.SetContains(key, jValue); } /// <summary> /// 随机获取key集合中的一个值 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="key"></param> /// <returns></returns> public T SetRandomMember<T>(string key) { key = AddSysCustomKey(key); var rValue = base.redis.SetRandomMember(key); return ConvertObj<T>(rValue); } /// <summary> /// 获取key所有值的集合 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public List<T> SetMembers<T>(string key) { key = AddSysCustomKey(key); var rValue = base.redis.SetMembers(key); return ConvetList<T>(rValue); } /// <summary> /// 删除key集合中指定的value /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public long SetRemove<T>(string key, params T[] value) { key = AddSysCustomKey(key); RedisValue[] valueList = base.ConvertRedisValue(value); return base.redis.SetRemove(key, valueList); } /// <summary> /// 随机删除key集合中的一个值,并返回该值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public T SetPop<T>(string key) { key = AddSysCustomKey(key); var rValue = base.redis.SetPop(key); return ConvertObj<T>(rValue); } /// <summary> /// 获取几个集合的并集 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public List<T> SetCombineUnion<T>(params string[] keys) { return _SetCombine<T>(SetOperation.Union, keys); } /// <summary> /// 获取几个集合的交集 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public List<T> SetCombineIntersect<T>(params string[] keys) { return _SetCombine<T>(SetOperation.Intersect, keys); } /// <summary> /// 获取几个集合的差集 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public List<T> SetCombineDifference<T>(params string[] keys) { return _SetCombine<T>(SetOperation.Difference, keys); } /// <summary> /// 获取几个集合的并集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public long SetCombineUnionAndStore(string destination, params string[] keys) { return _SetCombineAndStore(SetOperation.Union, destination, keys); } /// <summary> /// 获取几个集合的交集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public long SetCombineIntersectAndStore(string destination, params string[] keys) { return _SetCombineAndStore(SetOperation.Intersect, destination, keys); } /// <summary> /// 获取几个集合的差集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public long SetCombineDifferenceAndStore(string destination, params string[] keys) { return _SetCombineAndStore(SetOperation.Difference, destination, keys); } #endregion #region 异步方法 /// <summary> /// 在Key集合中添加一个value值 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="key">Key名称</param> /// <param name="value">值</param> /// <returns></returns> public async Task<bool> SetAddAsync<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return await base.redis.SetAddAsync(key, jValue); } /// <summary> /// 在Key集合中添加多个value值 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="key">Key名称</param> /// <param name="value">值列表</param> /// <returns></returns> public async Task<long> SetAddAsync<T>(string key, List<T> value) { key = AddSysCustomKey(key); RedisValue[] valueList = base.ConvertRedisValue(value.ToArray()); return await base.redis.SetAddAsync(key, valueList); } /// <summary> /// 获取key集合值的数量 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<long> SetLengthAsync(string key) { key = AddSysCustomKey(key); return await base.redis.SetLengthAsync(key); } /// <summary> /// 判断Key集合中是否包含指定的值 /// </summary> /// <typeparam name="T">值类型</typeparam> /// <param name="key"></param> /// <param name="value">要判断是值</param> /// <returns></returns> public async Task<bool> SetContainsAsync<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return await base.redis.SetContainsAsync(key, jValue); } /// <summary> /// 随机获取key集合中的一个值 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="key"></param> /// <returns></returns> public async Task<T> SetRandomMemberAsync<T>(string key) { key = AddSysCustomKey(key); var rValue = await base.redis.SetRandomMemberAsync(key); return ConvertObj<T>(rValue); } /// <summary> /// 获取key所有值的集合 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public async Task<List<T>> SetMembersAsync<T>(string key) { key = AddSysCustomKey(key); var rValue = await base.redis.SetMembersAsync(key); return ConvetList<T>(rValue); } /// <summary> /// 删除key集合中指定的value /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public async Task<long> SetRemoveAsync<T>(string key, params T[] value) { key = AddSysCustomKey(key); RedisValue[] valueList = base.ConvertRedisValue(value); return await base.redis.SetRemoveAsync(key, valueList); } /// <summary> /// 随机删除key集合中的一个值,并返回该值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public async Task<T> SetPopAsync<T>(string key) { key = AddSysCustomKey(key); var rValue = await base.redis.SetPopAsync(key); return ConvertObj<T>(rValue); } /// <summary> /// 获取几个集合的并集 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public async Task<List<T>> SetCombineUnionAsync<T>(params string[] keys) { return await _SetCombineAsync<T>(SetOperation.Union, keys); } /// <summary> /// 获取几个集合的交集 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public async Task<List<T>> SetCombineIntersectAsync<T>(params string[] keys) { return await _SetCombineAsync<T>(SetOperation.Intersect, keys); } /// <summary> /// 获取几个集合的差集 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public async Task<List<T>> SetCombineDifferenceAsync<T>(params string[] keys) { return await _SetCombineAsync<T>(SetOperation.Difference, keys); } /// <summary> /// 获取几个集合的并集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public async Task<long> SetCombineUnionAndStoreAsync(string destination, params string[] keys) { return await _SetCombineAndStoreAsync(SetOperation.Union, destination, keys); } /// <summary> /// 获取几个集合的交集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public async Task<long> SetCombineIntersectAndStoreAsync(string destination, params string[] keys) { return await _SetCombineAndStoreAsync(SetOperation.Intersect, destination, keys); } /// <summary> /// 获取几个集合的差集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public async Task<long> SetCombineDifferenceAndStoreAsync(string destination, params string[] keys) { return await _SetCombineAndStoreAsync(SetOperation.Difference, destination, keys); } #endregion #region 内部辅助方法 /// <summary> /// 获取几个集合的交叉并集合 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="operation">Union:并集 Intersect:交集 Difference:差集 详见 <see cref="SetOperation"/></param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> private List<T> _SetCombine<T>(SetOperation operation, params string[] keys) { RedisKey[] keyList = base.ConvertRedisKeysAddSysCustomKey(keys); var rValue = base.redis.SetCombine(operation, keyList); return ConvetList<T>(rValue); } /// <summary> /// 获取几个集合的交叉并集合,并保存到一个新Key中 /// </summary> /// <param name="operation">Union:并集 Intersect:交集 Difference:差集 详见 <see cref="SetOperation"/></param> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> private long _SetCombineAndStore(SetOperation operation, string destination, params string[] keys) { destination = AddSysCustomKey(destination); RedisKey[] keyList = base.ConvertRedisKeysAddSysCustomKey(keys); return base.redis.SetCombineAndStore(operation, destination, keyList); } /// <summary> /// 获取几个集合的交叉并集合 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="operation">Union:并集 Intersect:交集 Difference:差集 详见 <see cref="SetOperation"/></param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> private async Task<List<T>> _SetCombineAsync<T>(SetOperation operation, params string[] keys) { RedisKey[] keyList = base.ConvertRedisKeysAddSysCustomKey(keys); var rValue = await base.redis.SetCombineAsync(operation, keyList); return ConvetList<T>(rValue); } /// <summary> /// 获取几个集合的交叉并集合,并保存到一个新Key中 /// </summary> /// <param name="operation">Union:并集 Intersect:交集 Difference:差集 详见 <see cref="SetOperation"/></param> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> private async Task<long> _SetCombineAndStoreAsync(SetOperation operation, string destination, params string[] keys) { destination = AddSysCustomKey(destination); RedisKey[] keyList = base.ConvertRedisKeysAddSysCustomKey(keys); return await base.redis.SetCombineAndStoreAsync(operation, destination, keyList); } #endregion }
ZSet
redis 的zset类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Sorted Sets是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列 /// 1.带有权重的元素,比如一个游戏的用户得分排行榜 /// 2.比较复杂的数据结构,一般用到的场景不算太多 /// </summary> public class RedisSortedSetService : RedisBase { #region 构造函数 /// <summary> /// 初始化Redis的SortedSet有序数据结构操作 /// </summary> /// <param name="dbNum">操作的数据库索引0-64(需要在conf文件中配置)</param> public RedisSortedSetService(int? dbNum = null) : base(dbNum) { } #endregion #region 同步方法 /// <summary> /// 添加一个值到Key /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="score">排序分数,为空将获取集合中最大score加1</param> /// <returns></returns> public bool SortedSetAdd<T>(string key, T value, double? score = null) { key = AddSysCustomKey(key); double scoreNum = score ?? _GetScore(key); return base.redis.SortedSetAdd(key, ConvertJson<T>(value), scoreNum); } /// <summary> /// 添加一个集合到Key /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="score">排序分数,为空将获取集合中最大score加1</param> /// <returns></returns> public long SortedSetAdd<T>(string key, List<T> value, double? score = null) { key = AddSysCustomKey(key); double scoreNum = score ?? _GetScore(key); SortedSetEntry[] rValue = value.Select(o => new SortedSetEntry(ConvertJson<T>(o), scoreNum++)).ToArray(); return base.redis.SortedSetAdd(key, rValue); } /// <summary> /// 获取集合中的数量 /// </summary> /// <param name="key"></param> /// <returns></returns> public long SortedSetLength(string key) { key = AddSysCustomKey(key); return redis.SortedSetLength(key); } /// <summary> /// 获取指定起始值到结束值的集合数量 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="startValue">起始值</param> /// <param name="endValue">结束值</param> /// <returns></returns> public long SortedSetLengthByValue<T>(string key, T startValue, T endValue) { key = AddSysCustomKey(key); var sValue = ConvertJson<T>(startValue); var eValue = ConvertJson<T>(endValue); return redis.SortedSetLengthByValue(key, sValue, eValue); } /// <summary> /// 获取指定Key的排序Score值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public double? SortedSetScore<T>(string key, T value) { key = AddSysCustomKey(key); var rValue = ConvertJson<T>(value); return redis.SortedSetScore(key, rValue); } /// <summary> /// 获取指定Key中最小Score值 /// </summary> /// <param name="key"></param> /// <returns></returns> public double SortedSetMinScore(string key) { key = AddSysCustomKey(key); double dValue = 0; var rValue = base.redis.SortedSetRangeByRankWithScores(key, 0, 0, Order.Ascending).FirstOrDefault(); dValue = rValue != null ? rValue.Score : 0; return dValue; } /// <summary> /// 获取指定Key中最大Score值 /// </summary> /// <param name="key"></param> /// <returns></returns> public double SortedSetMaxScore(string key) { key = AddSysCustomKey(key); double dValue = 0; var rValue = base.redis.SortedSetRangeByRankWithScores(key, 0, 0, Order.Descending).FirstOrDefault(); dValue = rValue != null ? rValue.Score : 0; return dValue; } /// <summary> /// 删除Key中指定的值 /// </summary> /// <param name="key"></param> /// <param name="value"></param> public long SortedSetRemove<T>(string key, params T[] value) { key = AddSysCustomKey(key); var rValue = ConvertRedisValue<T>(value); return base.redis.SortedSetRemove(key, rValue); } /// <summary> /// 删除指定起始值到结束值的数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="startValue">起始值</param> /// <param name="endValue">结束值</param> /// <returns></returns> public long SortedSetRemoveRangeByValue<T>(string key, T startValue, T endValue) { key = AddSysCustomKey(key); var sValue = ConvertJson<T>(startValue); var eValue = ConvertJson<T>(endValue); return base.redis.SortedSetRemoveRangeByValue(key, sValue, eValue); } /// <summary> /// 删除 从 start 开始的 stop 条数据 /// </summary> /// <param name="key"></param> /// <param name="start"></param> /// <param name="stop"></param> /// <returns></returns> public long SortedSetRemoveRangeByRank(string key, long start, long stop) { key = AddSysCustomKey(key); return base.redis.SortedSetRemoveRangeByRank(key, start, stop); } /// <summary> /// 根据排序分数Score,删除从 start 开始的 stop 条数据 /// </summary> /// <param name="key"></param> /// <param name="start"></param> /// <param name="stop"></param> /// <returns></returns> public long SortedSetRemoveRangeByScore(string key, double start, double stop) { key = AddSysCustomKey(key); return base.redis.SortedSetRemoveRangeByScore(key, start, stop); } /// <summary> /// 获取从 start 开始的 stop 条数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="start">起始数</param> /// <param name="stop">-1表示到结束,0为1条</param> /// <param name="desc">是否按降序排列</param> /// <returns></returns> public List<T> SortedSetRangeByRank<T>(string key, long start = 0, long stop = -1, bool desc = false) { key = AddSysCustomKey(key); Order orderBy = desc ? Order.Descending : Order.Ascending; var rValue = base.redis.SortedSetRangeByRank(key, start, stop, orderBy); return ConvetList<T>(rValue); } /// <summary> /// 获取从 start 开始的 stop 条数据包含Score,返回数据格式:Key=值,Value = Score /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="start">起始数</param> /// <param name="stop">-1表示到结束,0为1条</param> /// <param name="desc">是否按降序排列</param> /// <returns></returns> public Dictionary<T, double> SortedSetRangeByRankWithScores<T>(string key, long start = 0, long stop = -1, bool desc = false) { key = AddSysCustomKey(key); Order orderBy = desc ? Order.Descending : Order.Ascending; var rValue = base.redis.SortedSetRangeByRankWithScores(key, start, stop, orderBy); Dictionary<T, double> dicList = new Dictionary<T, double>(); foreach (var item in rValue) { dicList.Add(ConvertObj<T>(item.Element), item.Score); } return dicList; } /// <summary> /// 根据Score排序 获取从 start 开始的 stop 条数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="start">起始数</param> /// <param name="stop">-1表示到结束,0为1条</param> /// <param name="desc">是否按降序排列</param> /// <returns></returns> public List<T> SortedSetRangeByScore<T>(string key, double start = 0, double stop = -1, bool desc = false) { key = AddSysCustomKey(key); Order orderBy = desc ? Order.Descending : Order.Ascending; var rValue = base.redis.SortedSetRangeByScore(key, start, stop, Exclude.None, orderBy); return ConvetList<T>(rValue); } /// <summary> /// 根据Score排序 获取从 start 开始的 stop 条数据包含Score,返回数据格式:Key=值,Value = Score /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="start">起始数</param> /// <param name="stop">-1表示到结束,0为1条</param> /// <param name="desc">是否按降序排列</param> /// <returns></returns> public Dictionary<T, double> SortedSetRangeByScoreWithScores<T>(string key, double start = 0, double stop = -1, bool desc = false) { key = AddSysCustomKey(key); Order orderBy = desc ? Order.Descending : Order.Ascending; var rValue = base.redis.SortedSetRangeByScoreWithScores(key, start, stop, Exclude.None, orderBy); Dictionary<T, double> dicList = new Dictionary<T, double>(); foreach (var item in rValue) { dicList.Add(ConvertObj<T>(item.Element), item.Score); } return dicList; } /// <summary> /// 获取指定起始值到结束值的数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="startValue">起始值</param> /// <param name="endValue">结束值</param> /// <returns></returns> public List<T> SortedSetRangeByValue<T>(string key, T startValue, T endValue) { key = AddSysCustomKey(key); var sValue = ConvertJson<T>(startValue); var eValue = ConvertJson<T>(endValue); var rValue = base.redis.SortedSetRangeByValue(key, sValue, eValue); return ConvetList<T>(rValue); } /// <summary> /// 获取几个集合的并集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public long SortedSetCombineUnionAndStore(string destination, params string[] keys) { return _SortedSetCombineAndStore(SetOperation.Union, destination, keys); } /// <summary> /// 获取几个集合的交集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public long SortedSetCombineIntersectAndStore(string destination, params string[] keys) { return _SortedSetCombineAndStore(SetOperation.Intersect, destination, keys); } //交集似乎并不支持 ///// <summary> ///// 获取几个集合的差集,并保存到一个新Key中 ///// </summary> ///// <param name="destination">保存的新Key名称</param> ///// <param name="keys">要操作的Key集合</param> ///// <returns></returns> //public long SortedSetCombineDifferenceAndStore(string destination, params string[] keys) //{ // return _SortedSetCombineAndStore(SetOperation.Difference, destination, keys); //} /// <summary> /// 修改指定Key和值的Scores在原值上减去scores,并返回最终Scores /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="scores"></param> /// <returns></returns> public double SortedSetDecrement<T>(string key, T value, double scores) { key = AddSysCustomKey(key); var rValue = ConvertJson<T>(value); return redis.SortedSetDecrement(key, rValue, scores); } /// <summary> /// 修改指定Key和值的Scores在原值上增加scores,并返回最终Scores /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="scores"></param> /// <returns></returns> public double SortedSetIncrement<T>(string key, T value, double scores) { key = AddSysCustomKey(key); var rValue = ConvertJson<T>(value); return redis.SortedSetIncrement(key, rValue, scores); } #endregion #region 异步方法 /// <summary> /// 添加一个值到Key /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="score">排序分数,为空将获取集合中最大score加1</param> /// <returns></returns> public async Task<bool> SortedSetAddAsync<T>(string key, T value, double? score = null) { key = AddSysCustomKey(key); double scoreNum = score ?? _GetScore(key); return await base.redis.SortedSetAddAsync(key, ConvertJson<T>(value), scoreNum); } /// <summary> /// 添加一个集合到Key /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="score">排序分数,为空将获取集合中最大score加1</param> /// <returns></returns> public async Task<long> SortedSetAddAsync<T>(string key, List<T> value, double? score = null) { key = AddSysCustomKey(key); double scoreNum = score ?? _GetScore(key); SortedSetEntry[] rValue = value.Select(o => new SortedSetEntry(ConvertJson<T>(o), scoreNum++)).ToArray(); return await base.redis.SortedSetAddAsync(key, rValue); } /// <summary> /// 获取集合中的数量 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<long> SortedSetLengthAsync(string key) { key = AddSysCustomKey(key); return await redis.SortedSetLengthAsync(key); } /// <summary> /// 获取指定起始值到结束值的集合数量 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="startValue">起始值</param> /// <param name="endValue">结束值</param> /// <returns></returns> public async Task<long> SortedSetLengthByValueAsync<T>(string key, T startValue, T endValue) { key = AddSysCustomKey(key); var sValue = ConvertJson<T>(startValue); var eValue = ConvertJson<T>(endValue); return await redis.SortedSetLengthByValueAsync(key, sValue, eValue); } /// <summary> /// 获取指定Key的排序Score值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public async Task<double?> SortedSetScoreAsync<T>(string key, T value) { key = AddSysCustomKey(key); var rValue = ConvertJson<T>(value); return await redis.SortedSetScoreAsync(key, rValue); } /// <summary> /// 获取指定Key中最小Score值 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<double> SortedSetMinScoreAsync(string key) { key = AddSysCustomKey(key); double dValue = 0; var rValue = (await base.redis.SortedSetRangeByRankWithScoresAsync(key, 0, 0, Order.Ascending)).FirstOrDefault(); dValue = rValue != null ? rValue.Score : 0; return dValue; } /// <summary> /// 获取指定Key中最大Score值 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<double> SortedSetMaxScoreAsync(string key) { key = AddSysCustomKey(key); double dValue = 0; var rValue = (await base.redis.SortedSetRangeByRankWithScoresAsync(key, 0, 0, Order.Descending)).FirstOrDefault(); dValue = rValue != null ? rValue.Score : 0; return dValue; } /// <summary> /// 删除Key中指定的值 /// </summary> /// <param name="key"></param> /// <param name="value"></param> public async Task<long> SortedSetRemoveAsync<T>(string key, params T[] value) { key = AddSysCustomKey(key); var rValue = ConvertRedisValue<T>(value); return await base.redis.SortedSetRemoveAsync(key, rValue); } /// <summary> /// 删除指定起始值到结束值的数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="startValue">起始值</param> /// <param name="endValue">结束值</param> /// <returns></returns> public async Task<long> SortedSetRemoveRangeByValueAsync<T>(string key, T startValue, T endValue) { key = AddSysCustomKey(key); var sValue = ConvertJson<T>(startValue); var eValue = ConvertJson<T>(endValue); return await base.redis.SortedSetRemoveRangeByValueAsync(key, sValue, eValue); } /// <summary> /// 删除 从 start 开始的 stop 条数据 /// </summary> /// <param name="key"></param> /// <param name="start"></param> /// <param name="stop"></param> /// <returns></returns> public async Task<long> SortedSetRemoveRangeByRankAsync(string key, long start, long stop) { key = AddSysCustomKey(key); return await base.redis.SortedSetRemoveRangeByRankAsync(key, start, stop); } /// <summary> /// 根据排序分数Score,删除从 start 开始的 stop 条数据 /// </summary> /// <param name="key"></param> /// <param name="start"></param> /// <param name="stop"></param> /// <returns></returns> public async Task<long> SortedSetRemoveRangeByScoreAsync(string key, double start, double stop) { key = AddSysCustomKey(key); return await base.redis.SortedSetRemoveRangeByScoreAsync(key, start, stop); } /// <summary> /// 获取从 start 开始的 stop 条数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="start">起始数</param> /// <param name="stop">-1表示到结束,0为1条</param> /// <param name="desc">是否按降序排列</param> /// <returns></returns> public async Task<List<T>> SortedSetRangeByRankAsync<T>(string key, long start = 0, long stop = -1, bool desc = false) { key = AddSysCustomKey(key); Order orderBy = desc ? Order.Descending : Order.Ascending; var rValue = await base.redis.SortedSetRangeByRankAsync(key, start, stop, orderBy); return ConvetList<T>(rValue); } /// <summary> /// 获取从 start 开始的 stop 条数据包含Score,返回数据格式:Key=值,Value = Score /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="start">起始数</param> /// <param name="stop">-1表示到结束,0为1条</param> /// <param name="desc">是否按降序排列</param> /// <returns></returns> public async Task<Dictionary<T, double>> SortedSetRangeByRankWithScoresAsync<T>(string key, long start = 0, long stop = -1, bool desc = false) { key = AddSysCustomKey(key); Order orderBy = desc ? Order.Descending : Order.Ascending; var rValue = await base.redis.SortedSetRangeByRankWithScoresAsync(key, start, stop, orderBy); Dictionary<T, double> dicList = new Dictionary<T, double>(); foreach (var item in rValue) { dicList.Add(ConvertObj<T>(item.Element), item.Score); } return dicList; } /// <summary> /// 根据Score排序 获取从 start 开始的 stop 条数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="start">起始数</param> /// <param name="stop">-1表示到结束,0为1条</param> /// <param name="desc">是否按降序排列</param> /// <returns></returns> public async Task<List<T>> SortedSetRangeByScoreAsync<T>(string key, double start = 0, double stop = -1, bool desc = false) { key = AddSysCustomKey(key); Order orderBy = desc ? Order.Descending : Order.Ascending; var rValue = await base.redis.SortedSetRangeByScoreAsync(key, start, stop, Exclude.None, orderBy); return ConvetList<T>(rValue); } /// <summary> /// 根据Score排序 获取从 start 开始的 stop 条数据包含Score,返回数据格式:Key=值,Value = Score /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="start">起始数</param> /// <param name="stop">-1表示到结束,0为1条</param> /// <param name="desc">是否按降序排列</param> /// <returns></returns> public async Task<Dictionary<T, double>> SortedSetRangeByScoreWithScoresAsync<T>(string key, double start = 0, double stop = -1, bool desc = false) { key = AddSysCustomKey(key); Order orderBy = desc ? Order.Descending : Order.Ascending; var rValue = await base.redis.SortedSetRangeByScoreWithScoresAsync(key, start, stop, Exclude.None, orderBy); Dictionary<T, double> dicList = new Dictionary<T, double>(); foreach (var item in rValue) { dicList.Add(ConvertObj<T>(item.Element), item.Score); } return dicList; } /// <summary> /// 获取指定起始值到结束值的数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="startValue">起始值</param> /// <param name="endValue">结束值</param> /// <returns></returns> public async Task<List<T>> SortedSetRangeByValueAsync<T>(string key, T startValue, T endValue) { key = AddSysCustomKey(key); var sValue = ConvertJson<T>(startValue); var eValue = ConvertJson<T>(endValue); var rValue = await base.redis.SortedSetRangeByValueAsync(key, sValue, eValue); return ConvetList<T>(rValue); } /// <summary> /// 获取几个集合的并集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public async Task<long> SortedSetCombineUnionAndStoreAsync(string destination, params string[] keys) { return await _SortedSetCombineAndStoreAsync(SetOperation.Union, destination, keys); } /// <summary> /// 获取几个集合的交集,并保存到一个新Key中 /// </summary> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> public async Task<long> SortedSetCombineIntersectAndStoreAsync(string destination, params string[] keys) { return await _SortedSetCombineAndStoreAsync(SetOperation.Intersect, destination, keys); } ///// <summary> ///// 获取几个集合的差集,并保存到一个新Key中 ///// </summary> ///// <param name="destination">保存的新Key名称</param> ///// <param name="keys">要操作的Key集合</param> ///// <returns></returns> //public async Task<long> SortedSetCombineDifferenceAndStoreAsync(string destination, params string[] keys) //{ // return await _SortedSetCombineAndStoreAsync(SetOperation.Difference, destination, keys); //} /// <summary> /// 修改指定Key和值的Scores在原值上减去scores,并返回最终Scores /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="scores"></param> /// <returns></returns> public async Task<double> SortedSetDecrementAsync<T>(string key, T value, double scores) { key = AddSysCustomKey(key); var rValue = ConvertJson<T>(value); return await base.redis.SortedSetDecrementAsync(key, rValue, scores); } /// <summary> /// 修改指定Key和值的Scores在原值上增加scores,并返回最终Scores /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="scores"></param> /// <returns></returns> public async Task<double> SortedSetIncrementAsync<T>(string key, T value, double scores) { key = AddSysCustomKey(key); var rValue = ConvertJson<T>(value); return await base.redis.SortedSetIncrementAsync(key, rValue, scores); } #endregion #region 内部辅助方法 /// <summary> /// 获取指定Key中最大Score值, /// </summary> /// <param name="key">key名称,注意要先添加上Key前缀</param> /// <returns></returns> private double _GetScore(string key) { double dValue = 0; var rValue = base.redis.SortedSetRangeByRankWithScores(key, 0, 0, Order.Descending).FirstOrDefault(); dValue = rValue != null ? rValue.Score : 0; return dValue + 1; } /// <summary> /// 获取几个集合的交叉并集合,并保存到一个新Key中 /// </summary> /// <param name="operation">Union:并集 Intersect:交集 Difference:差集 详见 <see cref="SetOperation"/></param> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> private long _SortedSetCombineAndStore(SetOperation operation, string destination, params string[] keys) { #region 查看源码,似乎并不支持Difference //RedisCommand command; //if (operation != SetOperation.Union) //{ // if (operation != SetOperation.Intersect) // { // throw new ArgumentOutOfRangeException("operation"); // } // command = RedisCommand.ZINTERSTORE; //} //else //{ // command = RedisCommand.ZUNIONSTORE; //} #endregion destination = AddSysCustomKey(destination); RedisKey[] keyList = base.ConvertRedisKeysAddSysCustomKey(keys); var rValue = base.redis.SortedSetCombineAndStore(operation, destination, keyList); return rValue; } /// <summary> /// 获取几个集合的交叉并集合,并保存到一个新Key中 /// </summary> /// <param name="operation">Union:并集 Intersect:交集 Difference:差集 详见 <see cref="SetOperation"/></param> /// <param name="destination">保存的新Key名称</param> /// <param name="keys">要操作的Key集合</param> /// <returns></returns> private async Task<long> _SortedSetCombineAndStoreAsync(SetOperation operation, string destination, params string[] keys) { destination = AddSysCustomKey(destination); RedisKey[] keyList = base.ConvertRedisKeysAddSysCustomKey(keys); var rValue = await base.redis.SortedSetCombineAndStoreAsync(operation, destination, keyList); return rValue; } #endregion }
List
redis 的List类型操作类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销, /// Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。 /// 一般是左进右出或者右进左出 /// </summary> public class RedisListService : RedisBase { #region 构造函数 /// <summary> /// 初始化Redis的List数据结构操作 /// </summary> /// <param name="dbNum">操作的数据库索引0-64(需要在conf文件中配置)</param> public RedisListService(int? dbNum = null) : base(dbNum) { } #endregion #region 同步方法 /// <summary> /// 从左侧向list中添加一个值,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public long ListLeftPush<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return base.redis.ListLeftPush(key, jValue); } /// <summary> /// 从左侧向list中添加多个值,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public long ListLeftPush<T>(string key, List<T> value) { key = AddSysCustomKey(key); RedisValue[] valueList = base.ConvertRedisValue(value.ToArray()); return base.redis.ListLeftPush(key, valueList); } /// <summary> /// 从右侧向list中添加一个值,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public long ListRightPush<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return base.redis.ListRightPush(key, jValue); } /// <summary> /// 从右侧向list中添加多个值,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public long ListRightPush<T>(string key, List<T> value) { key = AddSysCustomKey(key); RedisValue[] valueList = base.ConvertRedisValue(value.ToArray()); return base.redis.ListRightPush(key, valueList); } /// <summary> /// 从左侧向list中取出一个值并从list中删除 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public T ListLeftPop<T>(string key) { key = AddSysCustomKey(key); var rValue = base.redis.ListLeftPop(key); return base.ConvertObj<T>(rValue); } /// <summary> /// 从右侧向list中取出一个值并从list中删除 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public T ListRightPop<T>(string key) { key = AddSysCustomKey(key); var rValue = base.redis.ListRightPop(key); return base.ConvertObj<T>(rValue); } /// <summary> /// 从key的List中右侧取出一个值,并从左侧添加到destination集合中,且返回该数据对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key">要取出数据的List名称</param> /// <param name="destination">要添加到的List名称</param> /// <returns></returns> public T ListRightPopLeftPush<T>(string key, string destination) { key = AddSysCustomKey(key); destination = AddSysCustomKey(destination); var rValue = base.redis.ListRightPopLeftPush(key, destination); return base.ConvertObj<T>(rValue); } /// <summary> /// 在key的List指定值pivot之后插入value,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="pivot">索引值</param> /// <param name="value">要插入的值</param> /// <returns></returns> public long ListInsertAfter<T>(string key, T pivot, T value) { key = AddSysCustomKey(key); string pValue = ConvertJson(pivot); string jValue = ConvertJson(value); return base.redis.ListInsertAfter(key, pValue, jValue); } /// <summary> /// 在key的List指定值pivot之前插入value,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="pivot">索引值</param> /// <param name="value">要插入的值</param> /// <returns></returns> public long ListInsertBefore<T>(string key, T pivot, T value) { key = AddSysCustomKey(key); string pValue = ConvertJson(pivot); string jValue = ConvertJson(value); return base.redis.ListInsertBefore(key, pValue, jValue); } /// <summary> /// 从key的list中取出所有数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public List<T> ListRange<T>(string key) { key = AddSysCustomKey(key); var rValue = base.redis.ListRange(key); return base.ConvetList<T>(rValue); } /// <summary> /// 从key的List获取指定索引的值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="index"></param> /// <returns></returns> public T ListGetByIndex<T>(string key, long index) { key = AddSysCustomKey(key); var rValue = base.redis.ListGetByIndex(key, index); return base.ConvertObj<T>(rValue); } /// <summary> /// 获取key的list中数据个数 /// </summary> /// <param name="key"></param> /// <returns></returns> public long ListLength(string key) { key = AddSysCustomKey(key); return base.redis.ListLength(key); } /// <summary> /// 从key的List中移除指定的值,返回删除个数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public long ListRemove<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return base.redis.ListRemove(key, jValue); } #endregion #region 异步方法 /// <summary> /// 从左侧向list中添加一个值,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public async Task<long> ListLeftPushAsync<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return await base.redis.ListLeftPushAsync(key, jValue); } /// <summary> /// 从左侧向list中添加多个值,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public async Task<long> ListLeftPushAsync<T>(string key, List<T> value) { key = AddSysCustomKey(key); RedisValue[] valueList = base.ConvertRedisValue(value.ToArray()); return await base.redis.ListLeftPushAsync(key, valueList); } /// <summary> /// 从右侧向list中添加一个值,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public async Task<long> ListRightPushAsync<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return await base.redis.ListRightPushAsync(key, jValue); } /// <summary> /// 从右侧向list中添加多个值,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public async Task<long> ListRightPushAsync<T>(string key, List<T> value) { key = AddSysCustomKey(key); RedisValue[] valueList = base.ConvertRedisValue(value.ToArray()); return await base.redis.ListRightPushAsync(key, valueList); } /// <summary> /// 从左侧向list中取出一个值并从list中删除 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public async Task<T> ListLeftPopAsync<T>(string key) { key = AddSysCustomKey(key); var rValue = await base.redis.ListLeftPopAsync(key); return base.ConvertObj<T>(rValue); } /// <summary> /// 从右侧向list中取出一个值并从list中删除 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public async Task<T> ListRightPopAsync<T>(string key) { key = AddSysCustomKey(key); var rValue = await base.redis.ListRightPopAsync(key); return base.ConvertObj<T>(rValue); } /// <summary> /// 从key的List中右侧取出一个值,并从左侧添加到destination集合中,且返回该数据对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key">要取出数据的List名称</param> /// <param name="destination">要添加到的List名称</param> /// <returns></returns> public async Task<T> ListRightPopLeftPushAsync<T>(string key, string destination) { key = AddSysCustomKey(key); destination = AddSysCustomKey(destination); var rValue = await base.redis.ListRightPopLeftPushAsync(key, destination); return base.ConvertObj<T>(rValue); } /// <summary> /// 在key的List指定值pivot之后插入value,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="pivot">索引值</param> /// <param name="value">要插入的值</param> /// <returns></returns> public async Task<long> ListInsertAfterAsync<T>(string key, T pivot, T value) { key = AddSysCustomKey(key); string pValue = ConvertJson(pivot); string jValue = ConvertJson(value); return await base.redis.ListInsertAfterAsync(key, pValue, jValue); } /// <summary> /// 在key的List指定值pivot之前插入value,返回集合总数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="pivot">索引值</param> /// <param name="value">要插入的值</param> /// <returns></returns> public async Task<long> ListInsertBeforeAsync<T>(string key, T pivot, T value) { key = AddSysCustomKey(key); string pValue = ConvertJson(pivot); string jValue = ConvertJson(value); return await base.redis.ListInsertBeforeAsync(key, pValue, jValue); } /// <summary> /// 从key的list中取出所有数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public async Task<List<T>> ListRangeAsync<T>(string key) { key = AddSysCustomKey(key); var rValue = await base.redis.ListRangeAsync(key); return base.ConvetList<T>(rValue); } /// <summary> /// 从key的List获取指定索引的值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="index"></param> /// <returns></returns> public async Task<T> ListGetByIndexAsync<T>(string key, long index) { key = AddSysCustomKey(key); var rValue = await base.redis.ListGetByIndexAsync(key, index); return base.ConvertObj<T>(rValue); } /// <summary> /// 获取key的list中数据个数 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<long> ListLengthAsync(string key) { key = AddSysCustomKey(key); return await base.redis.ListLengthAsync(key); } /// <summary> /// 从key的List中移除指定的值,返回删除个数 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public async Task<long> ListRemoveAsync<T>(string key, T value) { key = AddSysCustomKey(key); string jValue = ConvertJson(value); return await base.redis.ListRemoveAsync(key, jValue); } #endregion }
使用
Console.WriteLine("*****************************************"); { using (RedisListService service = new RedisListService()) { service.KeyFulsh(); List<string> stringList = new List<string>(); for (int i = 0; i < 10; i++) { stringList.Add(string.Format($"放入任务{i}")); } service.ListLeftPush("test", "这是一个学生1"); service.ListLeftPush("test", "这是一个学生2"); service.ListLeftPush("test", "这是一个学生3"); service.ListLeftPush("test", "这是一个学生4"); service.ListLeftPush("test", "这是一个学生5"); service.ListLeftPush("test", "这是一个学生6"); service.ListLeftPush("task", stringList); Console.WriteLine(service.ListLength("test")); Console.WriteLine(service.ListLength("task")); var list = service.ListRange<string>("test"); Action act = new Action(() => { while (true) { Console.WriteLine("************请输入数据**************"); string testTask = Console.ReadLine(); service.ListLeftPush("test", testTask); } }); act.EndInvoke(act.BeginInvoke(null, null)); } }