一、NoSQL起源
NoSQL,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
Nosql为了弥补本地缓存的不足,是独立的第三方应用程序
本地缓存,当前进程的内存,把数据存起来,下次直接用,可以提升效率
1 容量有限,window下面,32位一个进程最多2G,或者3G 64位最多也就4G
2 多服务器直接需要缓存共享
需要分布式缓存---远程服务器内存管理数据,提供读写接口,效率高
分布式缓存:Memcached 最早流行
Nosql--Redis 主流方案
NoSql:非关系型数据库,Not Only Sql
数据的关系复杂:映射表,其实就冗余了,关系型数据开始累赘
再就是数据读取和写入压力,硬盘的速度满足不了,尤其是一些大数据量
所以产生了NoSql了,
特点:基于内存;
没有严格的数据格式,不是一行数据的列必须一样
丰富的类型,满足web2.0的需求
Redis:REmote DIctionary Server 远程字典服务器
基于内存管理(数据存在内存),实现了5种数据结构(分别应对各种具体需求),单线程模型的应用程序(单进程单线程),对外提供插入-查询-固化-集群功能
Redis-----SqlServer
redis-cli---SqlClient
REDIS支持N多个命令---Sql语句
RDM---可视化SQLClient
需要安装的nuget包
ServiceStack(1小时3600次请求--可破解)----Ado.Net
StackExchange 免费
其实更像ORM,封装了链接+命令
基于内存管理:速度快!不能当数据库; Redis还有个固化数据的功能,VitualMemory,把一些不经常访问是会存在硬盘 可以配置的;down掉会丢失数据,snapshot可以保存到硬盘,
AOF:数据变化记录日志,很少用
Redis毕竟不是数据库,只能用来提升性能,不能作为数据的最终依据
多线程模型:.Net应用都是的,尤其网站,可以更好的发挥硬件的能力,
但是也有线程冲突的问题和调度的成本
单线程模型:nodejs单线程,整个进程只有一个线程,线程就是执行流,性能低?实际上并非如此!一次网络请求操作==正则解析请求+加减乘除计算+数据库操作(发命令--等结果)+读文件(发命令--等结果)+调用接口(发命令---等结果),单线程都是事件驱动,发起命令就做下一件事儿,这个线程是完全不做等待的,一直在计算,单线程非常高;
单线程多进程的模式来提供集群服务
单线程最大的好处就是原子性操作,就是要么都成功,要么都失败,不会出现中间状态
redis每个命令都是原子性(因为单线程),不用考虑并发,不会出现中间状态
二、Redis五大结构理解
1)String: key-value的缓存,支持过期 value不超过512M
Redis是单线程的,比如SetAll&AppendToValue&GetValues&GetAndSetValue&IncrementValue&IncrementValueBy,这些看上去是组合命令,但实际上是一个具体的命令,是一个原子性的命令,不可能出现中间状态,可以应对一些并发情况
////// Redis管理中心 /// public class RedisManager { /// /// redis配置文件信息 /// private static RedisConfigInfo RedisConfigInfo = new RedisConfigInfo(); /// /// Redis客户端池化管理 /// private static PooledRedisClientManager prcManager; /// /// 静态构造方法,初始化链接池管理对象 /// static RedisManager() { CreateManager(); } /// /// 创建链接池管理对象 /// 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, }); } /// /// 客户端缓存操作对象 /// public static IRedisClient GetClient() { return prcManager.GetClient(); } }
////// redis配置文件信息 /// 也可以放到配置文件去 /// public sealed class RedisConfigInfo { /// /// 可写的Redis链接地址 /// format:ip1,ip2 /// /// 默认6379端口 /// public string WriteServerList = "127.0.0.1:6379"; /// /// 可读的Redis链接地址 /// format:ip1,ip2 /// public string ReadServerList = "127.0.0.1:6379"; /// /// 最大写链接数 /// public int MaxWritePoolSize = 60; /// /// 最大读链接数 /// public int MaxReadPoolSize = 60; /// /// 本地缓存到期时间,单位:秒 /// public int LocalCacheTime = 180; /// /// 自动重启 /// public bool AutoStart = true; /// /// 是否记录日志,该设置仅用于排查redis运行时出现的问题, /// 如redis工作正常,请关闭该项 /// public bool RecordeLog = false; }
1 ///2 /// RedisBase类,是redis操作的基类,继承自IDisposable接口,主要用于释放内存 3 /// 4 public abstract class RedisBase : IDisposable 5 { 6 public IRedisClient iClient { get; private set; } 7 /// 8 /// 构造时完成链接的打开 9 /// 10 public RedisBase() 11 { 12 iClient = RedisManager.GetClient(); 13 } 14 15 //public static IRedisClient iClient { get; private set; } 16 //static RedisBase() 17 //{ 18 // iClient = RedisManager.GetClient(); 19 //} 20 21 22 private bool _disposed = false; 23 protected virtual void Dispose(bool disposing) 24 { 25 if (!this._disposed) 26 { 27 if (disposing) 28 { 29 iClient.Dispose(); 30 iClient = null; 31 } 32 } 33 this._disposed = true; 34 } 35 public void Dispose() 36 { 37 Dispose(true); 38 GC.SuppressFinalize(this); 39 } 40 41 public void Transcation() 42 { 43 using (IRedisTransaction irt = this.iClient.CreateTransaction()) 44 { 45 try 46 { 47 irt.QueueCommand(r => r.Set("key", 20)); 48 irt.QueueCommand(r => r.Increment("key", 1)); 49 irt.Commit(); // 提交事务 50 } 51 catch (Exception ex) 52 { 53 irt.Rollback(); 54 throw ex; 55 } 56 } 57 } 58 59 60 /// 61 /// 清除全部数据 请小心 62 /// 63 public virtual void FlushAll() 64 { 65 iClient.FlushAll(); 66 } 67 68 /// 69 /// 保存数据DB文件到硬盘 70 /// 71 public void Save() 72 { 73 iClient.Save();//阻塞式save 74 } 75 76 /// 77 /// 异步保存数据DB文件到硬盘 78 /// 79 public void SaveAsync() 80 { 81 iClient.SaveAsync();//异步save 82 } 83 }
////// key-value 键值对:value可以是序列化的数据 /// public class RedisStringService : RedisBase { #region 赋值 /// /// 设置key的value /// public bool Set (string key, T value) { return base.iClient.Set (key, value); } /// /// 设置key的value并设置过期时间 /// public bool Set (string key, T value, DateTime dt) { return base.iClient.Set (key, value, dt); } /// /// 设置key的value并设置过期时间 /// public bool Set (string key, T value, TimeSpan sp) { return base.iClient.Set (key, value, sp); } /// /// 设置多个key/value /// public void Set(Dictionary<string, string> dic) { base.iClient.SetAll(dic); } #endregion #region 追加 /// /// 在原有key的value值之后追加value,没有就新增一项 /// public long Append(string key, string value) { return base.iClient.AppendToValue(key, value); } #endregion #region 获取值 /// /// 获取key的value值 /// public string Get(string key) { return base.iClient.GetValue(key); } /// /// 获取多个key的value值 /// public List<string> Get(List<string> keys) { return base.iClient.GetValues(keys); } /// /// 获取多个key的value值 /// public List Get (List<string> keys) { return base.iClient.GetValues (keys); } #endregion #region 获取旧值赋上新值 /// /// 获取旧值赋上新值 /// public string GetAndSetValue(string key, string value) { return base.iClient.GetAndSetValue(key, value); } #endregion #region 辅助方法 /// /// 获取值的长度 /// public long GetLength(string key) { return base.iClient.GetStringCount(key); } /// /// 自增1,返回自增后的值 /// public long Incr(string key) { return base.iClient.IncrementValue(key); } /// /// 自增count,返回自增后的值 /// public long IncrBy(string key, int count) { return base.iClient.IncrementValueBy(key, count); } /// /// 自减1,返回自减后的值 /// public long Decr(string key) { return base.iClient.DecrementValue(key); } /// /// 自减count ,返回自减后的值 /// /// /// /// public long DecrBy(string key, int count) { return base.iClient.DecrementValueBy(key, count); } #endregion }
2)Hash
////// Hash:类似dictionary,通过索引快速定位到指定元素的,耗时均等,跟string的区别在于不用反序列化,直接修改某个字段 /// string的话要么是 001:序列化整个实体 /// 要么是 001_name: 001_pwd: 多个key-value /// Hash的话,一个hashid-{key:value;key:value;key:value;} /// 可以一次性查找实体,也可以单个,还可以单个修改 /// public class RedisHashService : RedisBase { #region 添加 /// /// 向hashid集合中添加key/value /// public bool SetEntryInHash(string hashid, string key, string value) { return base.iClient.SetEntryInHash(hashid, key, value); } /// /// 如果hashid集合中存在key/value则不添加返回false, /// 如果不存在在添加key/value,返回true /// public bool SetEntryInHashIfNotExists(string hashid, string key, string value) { return base.iClient.SetEntryInHashIfNotExists(hashid, key, value); } /// /// 存储对象T t到hash集合中 /// 需要包含Id,然后用Id获取 /// public void StoreAsHash (T t) { base.iClient.StoreAsHash (t); } #endregion #region 获取 /// /// 获取对象T中ID为id的数据。 /// public T GetFromHash (object id) { return base.iClient.GetFromHash (id); } /// /// 获取所有hashid数据集的key/value数据集合 /// public Dictionary<string, string> GetAllEntriesFromHash(string hashid) { return base.iClient.GetAllEntriesFromHash(hashid); } /// /// 获取hashid数据集中的数据总数 /// public long GetHashCount(string hashid) { return base.iClient.GetHashCount(hashid); } /// /// 获取hashid数据集中所有key的集合 /// public List<string> GetHashKeys(string hashid) { return base.iClient.GetHashKeys(hashid); } /// /// 获取hashid数据集中的所有value集合 /// public List<string> GetHashValues(string hashid) { return base.iClient.GetHashValues(hashid); } /// /// 获取hashid数据集中,key的value数据 /// public string GetValueFromHash(string hashid, string key) { return base.iClient.GetValueFromHash(hashid, key); } /// /// 获取hashid数据集中,多个keys的value集合 /// public List<string> GetValuesFromHash(string hashid, string[] keys) { return base.iClient.GetValuesFromHash(hashid, keys); } #endregion #region 删除 /// /// 删除hashid数据集中的key数据 /// public bool RemoveEntryFromHash(string hashid, string key) { return base.iClient.RemoveEntryFromHash(hashid, key); } #endregion #region 其它 /// /// 判断hashid数据集中是否存在key的数据 /// public bool HashContainsEntry(string hashid, string key) { return base.iClient.HashContainsEntry(hashid, key); } /// /// 给hashid数据集key的value加countby,返回相加后的数据 /// public double IncrementValueInHash(string hashid, string key, double countBy) { return base.iClient.IncrementValueInHash(hashid, key, countBy); } #endregion }
3)Set
////// Set:用哈希表来保持字符串的唯一性,没有先后顺序,存储一些集合性的数据 /// 1.共同好友、二度好友 /// 2.利用唯一性,可以统计访问网站的所有独立 IP /// public class RedisSetService : RedisBase { #region 添加 /// /// key集合中添加value值 /// public void Add(string key, string value) { base.iClient.AddItemToSet(key, value); } /// /// key集合中添加list集合 /// public void Add(string key, List<string> list) { base.iClient.AddRangeToSet(key, list); } #endregion #region 获取 /// /// 随机获取key集合中的一个值 /// public string GetRandomItemFromSet(string key) { return base.iClient.GetRandomItemFromSet(key); } /// /// 获取key集合值的数量 /// public long GetCount(string key) { return base.iClient.GetSetCount(key); } /// /// 获取所有key集合的值 /// public HashSet<string> GetAllItemsFromSet(string key) { return base.iClient.GetAllItemsFromSet(key); } #endregion #region 删除 /// /// 随机删除key集合中的一个值 /// public string RandomRemoveItemFromSet(string key) { return base.iClient.PopItemFromSet(key); } /// /// 删除key集合中的value /// public void RemoveItemFromSet(string key, string value) { base.iClient.RemoveItemFromSet(key, value); } #endregion #region 其它 /// /// 从fromkey集合中移除值为value的值,并把value添加到tokey集合中 /// public void MoveBetweenSets(string fromkey, string tokey, string value) { base.iClient.MoveBetweenSets(fromkey, tokey, value); } /// /// 返回keys多个集合中的并集,返还hashset /// public HashSet<string> GetUnionFromSets(params string[] keys) { return base.iClient.GetUnionFromSets(keys); } /// /// 返回keys多个集合中的交集,返还hashset /// public HashSet<string> GetIntersectFromSets(params string[] keys) { return base.iClient.GetIntersectFromSets(keys); } /// /// 返回keys多个集合中的差集,返还hashset /// /// 原集合 /// 其他集合 /// 出现在原集合,但不包含在其他集合 public HashSet<string> GetDifferencesFromSet(string fromKey, params string[] keys) { return base.iClient.GetDifferencesFromSet(fromKey,keys); } /// /// keys多个集合中的并集,放入newkey集合中 /// public void StoreUnionFromSets(string newkey, string[] keys) { base.iClient.StoreUnionFromSets(newkey, keys); } /// /// 把fromkey集合中的数据与keys集合中的数据对比,fromkey集合中不存在keys集合中,则把这些不存在的数据放入newkey集合中 /// public void StoreDifferencesFromSet(string newkey, string fromkey, string[] keys) { base.iClient.StoreDifferencesFromSet(newkey, fromkey, keys); } #endregion }
4)ZSet
////// Sorted Sets是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列 /// 1.带有权重的元素,比如一个游戏的用户得分排行榜 /// 2.比较复杂的数据结构,一般用到的场景不算太多 /// public class RedisZSetService : RedisBase { #region 添加 /// /// 添加key/value,默认分数是从1.多*10的9次方以此递增的,自带自增效果 /// public bool Add(string key, string value) { return base.iClient.AddItemToSortedSet(key, value); } /// /// 添加key/value,并设置value的分数 /// public bool AddItemToSortedSet(string key, string value, double score) { return base.iClient.AddItemToSortedSet(key, value, score); } /// /// 为key添加values集合,values集合中每个value的分数设置为score /// public bool AddRangeToSortedSet(string key, List<string> values, double score) { return base.iClient.AddRangeToSortedSet(key, values, score); } /// /// 为key添加values集合,values集合中每个value的分数设置为score /// public bool AddRangeToSortedSet(string key, List<string> values, long score) { return base.iClient.AddRangeToSortedSet(key, values, score); } #endregion #region 获取 /// /// 获取key的所有集合 /// public List<string> GetAll(string key) { return base.iClient.GetAllItemsFromSortedSet(key); } /// /// 获取key的所有集合,倒叙输出 /// public List<string> GetAllDesc(string key) { return base.iClient.GetAllItemsFromSortedSetDesc(key); } /// /// 获取集合,带分数 /// public IDictionary<string, double> GetAllWithScoresFromSortedSet(string key) { return base.iClient.GetAllWithScoresFromSortedSet(key); } /// /// 获取key为value的下标值 /// public long GetItemIndexInSortedSet(string key, string value) { return base.iClient.GetItemIndexInSortedSet(key, value); } /// /// 倒叙排列获取key为value的下标值 /// public long GetItemIndexInSortedSetDesc(string key, string value) { return base.iClient.GetItemIndexInSortedSetDesc(key, value); } /// /// 获取key为value的分数 /// public double GetItemScoreInSortedSet(string key, string value) { return base.iClient.GetItemScoreInSortedSet(key, value); } /// /// 获取key所有集合的数据总数 /// public long GetSortedSetCount(string key) { return base.iClient.GetSortedSetCount(key); } /// /// key集合数据从分数为fromscore到分数为toscore的数据总数 /// public long GetSortedSetCount(string key, double fromScore, double toScore) { return base.iClient.GetSortedSetCount(key, fromScore, toScore); } /// /// 获取key集合从高分到低分排序数据,分数从fromscore到分数为toscore的数据 /// public List<string> GetRangeFromSortedSetByHighestScore(string key, double fromscore, double toscore) { return base.iClient.GetRangeFromSortedSetByHighestScore(key, fromscore, toscore); } /// /// 获取key集合从低分到高分排序数据,分数从fromscore到分数为toscore的数据 /// public List<string> GetRangeFromSortedSetByLowestScore(string key, double fromscore, double toscore) { return base.iClient.GetRangeFromSortedSetByLowestScore(key, fromscore, toscore); } /// /// 获取key集合从高分到低分排序数据,分数从fromscore到分数为toscore的数据,带分数 /// public IDictionary<string, double> GetRangeWithScoresFromSortedSetByHighestScore(string key, double fromscore, double toscore) { return base.iClient.GetRangeWithScoresFromSortedSetByHighestScore(key, fromscore, toscore); } /// /// 获取key集合从低分到高分排序数据,分数从fromscore到分数为toscore的数据,带分数 /// public IDictionary<string, double> GetRangeWithScoresFromSortedSetByLowestScore(string key, double fromscore, double toscore) { return base.iClient.GetRangeWithScoresFromSortedSetByLowestScore(key, fromscore, toscore); } /// /// 获取key集合数据,下标从fromRank到分数为toRank的数据 /// public List<string> GetRangeFromSortedSet(string key, int fromRank, int toRank) { return base.iClient.GetRangeFromSortedSet(key, fromRank, toRank); } /// /// 获取key集合倒叙排列数据,下标从fromRank到分数为toRank的数据 /// public List<string> GetRangeFromSortedSetDesc(string key, int fromRank, int toRank) { return base.iClient.GetRangeFromSortedSetDesc(key, fromRank, toRank); } /// /// 获取key集合数据,下标从fromRank到分数为toRank的数据,带分数 /// public IDictionary<string, double> GetRangeWithScoresFromSortedSet(string key, int fromRank, int toRank) { return base.iClient.GetRangeWithScoresFromSortedSet(key, fromRank, toRank); } /// /// 获取key集合倒叙排列数据,下标从fromRank到分数为toRank的数据,带分数 /// public IDictionary<string, double> GetRangeWithScoresFromSortedSetDesc(string key, int fromRank, int toRank) { return base.iClient.GetRangeWithScoresFromSortedSetDesc(key, fromRank, toRank); } #endregion #region 删除 /// /// 删除key为value的数据 /// public bool RemoveItemFromSortedSet(string key, string value) { return base.iClient.RemoveItemFromSortedSet(key, value); } /// /// 删除下标从minRank到maxRank的key集合数据 /// public long RemoveRangeFromSortedSet(string key, int minRank, int maxRank) { return base.iClient.RemoveRangeFromSortedSet(key, minRank, maxRank); } /// /// 删除分数从fromscore到toscore的key集合数据 /// public long RemoveRangeFromSortedSetByScore(string key, double fromscore, double toscore) { return base.iClient.RemoveRangeFromSortedSetByScore(key, fromscore, toscore); } /// /// 删除key集合中分数最大的数据 /// public string PopItemWithHighestScoreFromSortedSet(string key) { return base.iClient.PopItemWithHighestScoreFromSortedSet(key); } /// /// 删除key集合中分数最小的数据 /// public string PopItemWithLowestScoreFromSortedSet(string key) { return base.iClient.PopItemWithLowestScoreFromSortedSet(key); } #endregion #region 其它 /// /// 判断key集合中是否存在value数据 /// public bool SortedSetContainsItem(string key, string value) { return base.iClient.SortedSetContainsItem(key, value); } /// /// 为key集合值为value的数据,分数加scoreby,返回相加后的分数 /// public double IncrementItemInSortedSet(string key, string value, double scoreBy) { return base.iClient.IncrementItemInSortedSet(key, value, scoreBy); } /// /// 获取keys多个集合的交集,并把交集添加的newkey集合中,返回交集数据的总数 /// public long StoreIntersectFromSortedSets(string newkey, string[] keys) { return base.iClient.StoreIntersectFromSortedSets(newkey, keys); } /// /// 获取keys多个集合的并集,并把并集数据添加到newkey集合中,返回并集数据的总数 /// public long StoreUnionFromSortedSets(string newkey, string[] keys) { return base.iClient.StoreUnionFromSortedSets(newkey, keys); } #endregion }
5) List
////// Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销, /// Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。 /// public class RedisListService : RedisBase { #region 赋值 /// /// 从左侧向list中添加值 /// public void LPush(string key, string value) { base.iClient.PushItemToList(key, value); } /// /// 从左侧向list中添加值,并设置过期时间 /// public void LPush(string key, string value, DateTime dt) { base.iClient.PushItemToList(key, value); base.iClient.ExpireEntryAt(key, dt); } /// /// 从左侧向list中添加值,设置过期时间 /// public void LPush(string key, string value, TimeSpan sp) { base.iClient.PushItemToList(key, value); base.iClient.ExpireEntryIn(key, sp); } /// /// 从右侧向list中添加值 /// public void RPush(string key, string value) { base.iClient.PrependItemToList(key, value); } /// /// 从右侧向list中添加值,并设置过期时间 /// public void RPush(string key, string value, DateTime dt) { base.iClient.PrependItemToList(key, value); base.iClient.ExpireEntryAt(key, dt); } /// /// 从右侧向list中添加值,并设置过期时间 /// public void RPush(string key, string value, TimeSpan sp) { base.iClient.PrependItemToList(key, value); base.iClient.ExpireEntryIn(key, sp); } /// /// 添加key/value /// public void Add(string key, string value) { base.iClient.AddItemToList(key, value); } /// /// 添加key/value ,并设置过期时间 /// public void Add(string key, string value, DateTime dt) { base.iClient.AddItemToList(key, value); base.iClient.ExpireEntryAt(key, dt); } /// /// 添加key/value。并添加过期时间 /// public void Add(string key, string value, TimeSpan sp) { base.iClient.AddItemToList(key, value); base.iClient.ExpireEntryIn(key, sp); } /// /// 为key添加多个值 /// public void Add(string key, List<string> values) { base.iClient.AddRangeToList(key, values); } /// /// 为key添加多个值,并设置过期时间 /// public void Add(string key, List<string> values, DateTime dt) { base.iClient.AddRangeToList(key, values); base.iClient.ExpireEntryAt(key, dt); } /// /// 为key添加多个值,并设置过期时间 /// public void Add(string key, List<string> values, TimeSpan sp) { base.iClient.AddRangeToList(key, values); base.iClient.ExpireEntryIn(key, sp); } #endregion #region 获取值 /// /// 获取list中key包含的数据数量 /// public long Count(string key) { return base.iClient.GetListCount(key); } /// /// 获取key包含的所有数据集合 /// public List<string> Get(string key) { return base.iClient.GetAllItemsFromList(key); } /// /// 获取key中下标为star到end的值集合 /// public List<string> Get(string key, int star, int end) { return base.iClient.GetRangeFromList(key, star, end); } #endregion #region 阻塞命令 /// /// 阻塞命令:从list为key的尾部移除一个值,并返回移除的值,阻塞时间为sp /// public string BlockingPopItemFromList(string key, TimeSpan? sp) { return base.iClient.BlockingPopItemFromList(key, sp); } /// /// 阻塞命令:从多个list中尾部移除一个值,并返回移除的值&key,阻塞时间为sp /// public ItemRef BlockingPopItemFromLists(string[] keys, TimeSpan? sp) { return base.iClient.BlockingPopItemFromLists(keys, sp); } /// /// 阻塞命令:从list中keys的尾部移除一个值,并返回移除的值,阻塞时间为sp /// public string BlockingDequeueItemFromList(string key, TimeSpan? sp) { return base.iClient.BlockingDequeueItemFromList(key, sp); } /// /// 阻塞命令:从多个list中尾部移除一个值,并返回移除的值&key,阻塞时间为sp /// public ItemRef BlockingDequeueItemFromLists(string[] keys, TimeSpan? sp) { return base.iClient.BlockingDequeueItemFromLists(keys, sp); } /// /// 阻塞命令:从list中一个fromkey的尾部移除一个值,添加到另外一个tokey的头部,并返回移除的值,阻塞时间为sp /// public string BlockingPopAndPushItemBetweenLists(string fromkey, string tokey, TimeSpan? sp) { return base.iClient.BlockingPopAndPushItemBetweenLists(fromkey, tokey, sp); } #endregion #region 删除 /// /// 从尾部移除数据,返回移除的数据 /// public string PopItemFromList(string key) { var sa = base.iClient.CreateSubscription(); return base.iClient.PopItemFromList(key); } /// /// 从尾部移除数据,返回移除的数据 /// public string DequeueItemFromList(string key) { return base.iClient.DequeueItemFromList(key); } /// /// 移除list中,key/value,与参数相同的值,并返回移除的数量 /// public long RemoveItemFromList(string key, string value) { return base.iClient.RemoveItemFromList(key, value); } /// /// 从list的尾部移除一个数据,返回移除的数据 /// public string RemoveEndFromList(string key) { return base.iClient.RemoveEndFromList(key); } /// /// 从list的头部移除一个数据,返回移除的值 /// public string RemoveStartFromList(string key) { return base.iClient.RemoveStartFromList(key); } #endregion #region 其它 /// /// 从一个list的尾部移除一个数据,添加到另外一个list的头部,并返回移动的值 /// public string PopAndPushItemBetweenLists(string fromKey, string toKey) { return base.iClient.PopAndPushItemBetweenLists(fromKey, toKey); } #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 }