封装一个Redis服务组件
结构说明
ServiceCollectionExtensions类
1 using com.project.Redis.Common; 2 using Microsoft.Extensions.Configuration; 3 using Microsoft.Extensions.DependencyInjection; 4 using System; 5 6 namespace com.project.Redis 7 { 8 public static class ServiceCollectionExtensions 9 { 10 public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration, string sectionName = "Redis") 11 { 12 if (services == null) 13 { 14 throw new ArgumentNullException(nameof(services)); 15 } 16 services.Configure<RedisOptions>(configuration.GetSection(sectionName)); 17 services.AddSingleton<IRedisBuilder, RedisBuilder>(); 18 return services; 19 } 20 21 //public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration) 22 //{ 23 // return new RedisBuilder(services, configuration); 24 //} 25 } 26 }
RedisOptions类
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace com.project.Redis.Common 6 { 7 public class RedisOptions 8 { 9 public string Ip { get; set; } 10 public int Port { get; set; } 11 public string Password { get; set; } 12 public int DefaultDatabase { get; set; } = 1; 13 14 /// <summary> 15 /// 需要连接的其他Database索引 16 /// </summary> 17 public string OtherDatabase { get; set; } = string.Empty; 18 19 /// <summary> 20 /// The asynchronous method automatically uses pipeline, and the 10W concurrent time is 450ms (welcome to feedback) 默认值:false 21 /// </summary> 22 public bool AsyncPipeline { get; set; } = false; 23 24 /// <summary> 25 /// 默认连接池数量是50个,也就是说一个微服务通过单例创建redisclient以后,通过CLIENT LIST可以查看到redisserver的连接数为50个。 26 /// 默认值:50 27 /// </summary> 28 public int Poolsize { get; set; } = 50; 29 30 /// <summary> 31 /// Idle time of elements in the connection pool (MS), suitable for connecting to remote redis server 32 /// 默认值:2000 33 /// </summary> 34 public int IdleTimeout { get; set; } = 2000; 35 36 /// <summary> 37 /// Connection timeout (MS) 38 /// 默认值:5000 39 /// </summary> 40 public int ConnectTimeout { get; set; } = 5000; 41 42 /// <summary> 43 /// Send / receive timeout (MS) 44 /// 默认值:10000 45 /// </summary> 46 public int SyncTimeout { get; set; } = 10000; 47 48 /// <summary> 49 /// Preheat connections, receive values such as preheat = 5 preheat 5 connections 50 /// 默认值:5 51 /// </summary> 52 public int Preheat { get; set; } = 5; 53 54 /// <summary> 55 /// Follow system exit event to release automatically 56 /// 默认值:true 57 /// </summary> 58 public bool AutoDispose { get; set; } = true; 59 60 /// <summary> 61 /// Enable encrypted transmission 62 /// 默认值:false 63 /// </summary> 64 public bool SSL { get; set; } = false; 65 66 /// <summary> 67 /// 是否尝试集群模式,阿里云、腾讯云集群需要设置此选项为 false 68 /// true 69 /// </summary> 70 public bool Testcluster { get; set; } = true; 71 72 /// <summary> 73 /// Execution error, retry attempts 74 /// 默认值:0 75 /// </summary> 76 public int Tryit { get; set; } = 0; 77 78 /// <summary> 79 /// Connection name, use client list command to view 80 /// 客户端连接名称,在RedisServer上面使用Client list可以查看 81 /// 默认值:<Empty> 82 /// </summary> 83 public string Name { get; set; } = string.Empty; 84 85 /// <summary> 86 /// key前辍,所有方法都会附带此前辍,csredis.Set(prefix + "key", 111); 87 /// 默认值:<Empty> 88 /// </summary> 89 public string Prefix { get; set; } = string.Empty; 90 91 /// <summary> 92 /// 是否为redis集群,redis采用哨兵机制进行集群 93 /// 默认值:false 94 /// </summary> 95 public bool RedisCluster { get; set; } = false; 96 } 97 }
IRedisBuilder 接口类
1 namespace com.project.Redis 2 { 3 public interface IRedisBuilder 4 { 5 /// <summary> 6 /// 得到CSRedisClient操作对象 7 /// </summary> 8 /// <returns></returns> 9 public CSRedis.CSRedisClient GetCSRedisClient(); 10 /// <summary> 11 /// 得到CSRedisClient操作对象 12 /// </summary> 13 /// <param name="databaseIndex">database Index</param> 14 /// <returns></returns> 15 public CSRedis.CSRedisClient GetCSRedisClient(int databaseIndex); 16 } 17 }
RedisBuilder 类
1 using com.project.Redis.Common; 2 using CSRedis; 3 using Microsoft.Extensions.Options; 4 using System; 5 using System.Collections.Generic; 6 7 namespace com.project.Redis 8 { 9 /// <summary> 10 /// CSRedis客户端内部已经实现了连接池的管理, 11 /// 因此在全局单例CsRedisClient对象即可 12 /// </summary> 13 public class RedisBuilder : IRedisBuilder 14 { 15 private CSRedis.CSRedisClient _client; 16 /// <summary> 17 /// Redis操作客户端对象集合 18 /// </summary> 19 private Dictionary<int, CSRedis.CSRedisClient> _csredisclients; 20 /// <summary> 21 /// Redis连接参数 22 /// </summary> 23 private readonly RedisOptions _redisOptions; 24 25 public RedisBuilder(IOptionsMonitor<RedisOptions> optionAccs) 26 { 27 _redisOptions = optionAccs.CurrentValue; 28 //127.0.0.1[:6379],password=123456,defaultDatabase=13,poolsize=50,ssl=false,writeBuffer=10240,prefix=key前辍 29 string connectionStringPrefix = string.Format("{0}:{1},password={2},poolsize={3},connectTimeout={4},ssl={5},writeBuffer=10240", 30 _redisOptions.Ip, 31 _redisOptions.Port, 32 _redisOptions.Password, 33 _redisOptions.Poolsize, 34 _redisOptions.ConnectTimeout, 35 _redisOptions.SSL); 36 37 //测试 redis-cluster 不能设置 defaultDatabase 38 string defaultConnectionString = connectionStringPrefix; 39 if (!_redisOptions.RedisCluster) 40 defaultConnectionString += $",defaultDatabase={_redisOptions.DefaultDatabase}"; 41 if (!string.IsNullOrEmpty(_redisOptions.Prefix)) 42 defaultConnectionString += $",prefix={_redisOptions.Prefix}"; 43 _client = new CSRedis.CSRedisClient(defaultConnectionString); 44 45 if (!string.IsNullOrEmpty(_redisOptions.OtherDatabase)) 46 { 47 _csredisclients = new Dictionary<int, CSRedisClient>(); 48 if (_redisOptions.OtherDatabase.IndexOf(",") == -1) 49 { 50 string otherDatabaseConnectionString = connectionStringPrefix; 51 otherDatabaseConnectionString += $",defaultDatabase={_redisOptions.OtherDatabase}"; 52 if (!string.IsNullOrEmpty(_redisOptions.Prefix)) 53 otherDatabaseConnectionString += $",prefix={_redisOptions.Prefix}"; 54 _csredisclients.Add(Convert.ToInt32(_redisOptions.OtherDatabase), new CSRedis.CSRedisClient(otherDatabaseConnectionString)); 55 } 56 else 57 { 58 string[] otherDatabaseIndex = _redisOptions.OtherDatabase.Split(","); 59 foreach (string index in otherDatabaseIndex) 60 { 61 string otherDatabaseConnectionString = connectionStringPrefix; 62 otherDatabaseConnectionString += $",defaultDatabase={index}"; 63 if (!string.IsNullOrEmpty(_redisOptions.Prefix)) 64 otherDatabaseConnectionString += $",prefix={_redisOptions.Prefix}"; 65 _csredisclients.Add(Convert.ToInt32(index), new CSRedis.CSRedisClient(otherDatabaseConnectionString)); 66 } 67 } 68 } 69 } 70 71 /// <summary> 72 /// 得到CSRedisClient操作对象 73 /// </summary> 74 /// <returns></returns> 75 public CSRedisClient GetCSRedisClient() 76 { 77 return _client; 78 } 79 80 /// <summary> 81 /// 得到CSRedisClient操作对象 82 /// </summary> 83 /// <param name="databaseIndex">database Index</param> 84 /// <returns></returns> 85 public CSRedisClient GetCSRedisClient(int databaseIndex) 86 { 87 return _csredisclients[databaseIndex]; 88 } 89 } 90 }
CSRedisClient类
1 using CSRedis.Internal.ObjectPool; 2 using System; 3 using System.Collections.Concurrent; 4 using System.Collections.Generic; 5 using System.Diagnostics; 6 using System.Linq; 7 using System.Text.RegularExpressions; 8 using System.Threading; 9 using System.Threading.Tasks; 10 11 #if net40 12 #else 13 namespace CSRedis 14 { 15 public partial class CSRedisClient 16 { 17 18 ConcurrentDictionary<string, AutoPipe> _autoPipe = new ConcurrentDictionary<string, AutoPipe>(); 19 class AutoPipe 20 { 21 public Object<RedisClient> Client; 22 public long GetTimes; 23 public long TimesZore; 24 public bool IsSingleEndPipe; 25 public Exception ReturnException; 26 } 27 async Task<AutoPipe> GetClientAsync(RedisClientPool pool) 28 { 29 if (pool._policy._asyncPipeline == false) 30 return new AutoPipe { Client = await pool.GetAsync(), GetTimes = 1, TimesZore = 0, IsSingleEndPipe = false }; 31 32 if (_autoPipe.TryGetValue(pool.Key, out var ap) && ap.IsSingleEndPipe == false) 33 { 34 if (pool.UnavailableException != null) 35 throw new Exception($"【{pool._policy.Name}】状态不可用,等待后台检查程序恢复方可使用。{pool.UnavailableException?.Message}", pool.UnavailableException); 36 Interlocked.Increment(ref ap.GetTimes); 37 return ap; 38 } 39 ap = new AutoPipe { Client = await pool.GetAsync(), GetTimes = 1, TimesZore = 0, IsSingleEndPipe = false }; 40 if (_autoPipe.TryAdd(pool.Key, ap)) 41 { 42 ap.Client.Value._asyncPipe = new ConcurrentQueue<TaskCompletionSource<object>>(); 43 new Thread(() => 44 { 45 var rc = ap.Client.Value; 46 47 void trySetException(Exception ex) 48 { 49 pool.SetUnavailable(ex); 50 while (rc._asyncPipe?.IsEmpty == false) 51 { 52 TaskCompletionSource<object> trytsc = null; 53 if (rc._asyncPipe?.TryDequeue(out trytsc) == true) 54 trytsc.TrySetException(ex); 55 } 56 rc._asyncPipe = null; 57 pool.Return(ap.Client); 58 _autoPipe.TryRemove(pool.Key, out var oldap); 59 } 60 while (true) 61 { 62 Thread.CurrentThread.Join(1); 63 if (rc._asyncPipe?.IsEmpty == false) 64 { 65 try 66 { 67 var ret = rc.EndPipe(); 68 if (ret.Length == 1) ap.IsSingleEndPipe = true; 69 else if (ret.Length > 1) ap.IsSingleEndPipe = false; 70 foreach (var rv in ret) 71 { 72 TaskCompletionSource<object> trytsc = null; 73 if (rc._asyncPipe?.TryDequeue(out trytsc) == true) 74 trytsc.TrySetResult(rv); 75 } 76 } 77 catch (Exception ex) 78 { 79 trySetException(ex); 80 return; 81 } 82 continue; 83 } 84 85 if (ap.ReturnException != null) 86 { 87 trySetException(ap.ReturnException); 88 return; 89 } 90 var tmpTimes = Interlocked.Increment(ref ap.TimesZore); 91 if (tmpTimes >= 10) ap.IsSingleEndPipe = false; 92 if (tmpTimes >= 1000) 93 { 94 rc._asyncPipe = null; 95 pool.Return(ap.Client, ap.ReturnException); 96 _autoPipe.TryRemove(pool.Key, out var oldap); 97 break; 98 } 99 } 100 }).Start(); 101 } 102 return ap; 103 } 104 void ReturnClient(AutoPipe ap, Object<RedisClient> obj, RedisClientPool pool, Exception ex) 105 { 106 if (ap == null) return; 107 var times = Interlocked.Decrement(ref ap.GetTimes); 108 if (times <= 0) 109 Interlocked.Exchange(ref ap.TimesZore, 0); 110 ap.ReturnException = ex; 111 if (_autoPipe.TryGetValue(pool.Key, out var dicap) == false || dicap != ap) 112 pool.Return(ap.Client, ap.ReturnException); 113 } 114 115 async Task<T> GetAndExecuteAsync<T>(RedisClientPool pool, Func<Object<RedisClient>, Task<T>> handerAsync, int jump = 100, int errtimes = 0) 116 { 117 AutoPipe ap = null; 118 Object<RedisClient> obj = null; 119 Exception ex = null; 120 var redirect = ParseClusterRedirect(null); 121 try 122 { 123 ap = await GetClientAsync(pool); 124 obj = ap.Client; 125 while (true) 126 { //因网络出错重试,默认1次 127 try 128 { 129 var ret = await handerAsync(obj); 130 return ret; 131 } 132 catch (RedisException ex3) 133 { 134 redirect = ParseClusterRedirect(ex3); //官方集群跳转 135 if (redirect == null || jump <= 0) 136 { 137 ex = ex3; 138 if (SentinelManager != null && ex.Message.Contains("READONLY")) 139 { //哨兵轮询 140 if (pool.SetUnavailable(ex) == true) 141 BackgroundGetSentinelMasterValue(); 142 } 143 throw ex; 144 } 145 break; 146 } 147 catch (Exception ex2) 148 { 149 ex = ex2; 150 if (pool.UnavailableException != null) throw ex; 151 var isPong = false; 152 try 153 { 154 await obj.Value.PingAsync(); 155 isPong = true; 156 } 157 catch 158 { 159 obj.ResetValue(); 160 } 161 162 if (isPong == false || ++errtimes > pool._policy._tryit) 163 { 164 if (SentinelManager != null) 165 { //哨兵轮询 166 if (pool.SetUnavailable(ex) == true) 167 BackgroundGetSentinelMasterValue(); 168 throw new Exception($"Redis Sentinel Master is switching:{ex.Message}"); 169 } 170 throw ex; //重试次数完成 171 } 172 else 173 { 174 ex = null; 175 Trace.WriteLine($"csredis tryit ({errtimes}) ..."); 176 } 177 } 178 } 179 } 180 finally 181 { 182 ReturnClient(ap, obj, pool, ex); 183 //pool.Return(obj, ex); 184 } 185 if (redirect == null) 186 return await GetAndExecuteAsync<T>(pool, handerAsync, jump - 1, errtimes); 187 188 var redirectHanderAsync = redirect.Value.isMoved ? handerAsync : async redirectObj => 189 { 190 await redirectObj.Value.CallAsync("ASKING"); 191 return await handerAsync(redirectObj); 192 }; 193 return await GetAndExecuteAsync<T>(GetRedirectPool(redirect.Value, pool), redirectHanderAsync, jump - 1); 194 } 195 196 async Task<T> NodesNotSupportAsync<T>(string[] keys, T defaultValue, Func<Object<RedisClient>, string[], Task<T>> callbackAsync) 197 { 198 if (keys == null || keys.Any() == false) return defaultValue; 199 var rules = Nodes.Count > 1 ? keys.Select(a => NodeRuleRaw(a)).Distinct() : new[] { Nodes.FirstOrDefault().Key }; 200 if (rules.Count() > 1) throw new Exception("由于开启了分区模式,keys 分散在多个节点,无法使用此功能"); 201 var pool = Nodes.TryGetValue(rules.First(), out var b) ? b : Nodes.First().Value; 202 string[] rkeys = new string[keys.Length]; 203 for (int a = 0; a < keys.Length; a++) rkeys[a] = string.Concat(pool.Prefix, keys[a]); 204 if (rkeys.Length == 0) return defaultValue; 205 return await GetAndExecuteAsync(pool, conn => callbackAsync(conn, rkeys)); 206 } 207 Task<T> NodesNotSupportAsync<T>(string key, Func<Object<RedisClient>, string, Task<T>> callback) 208 { 209 if (IsMultiNode) throw new Exception("由于开启了分区模式,无法使用此功能"); 210 return ExecuteScalarAsync<T>(key, callback); 211 } 212 213 214 #region 缓存壳 215 /// <summary> 216 /// 缓存壳 217 /// </summary> 218 /// <typeparam name="T">缓存类型</typeparam> 219 /// <param name="key">不含prefix前辍</param> 220 /// <param name="timeoutSeconds">缓存秒数</param> 221 /// <param name="getDataAsync">获取源数据的函数</param> 222 /// <returns></returns> 223 async public Task<T> CacheShellAsync<T>(string key, int timeoutSeconds, Func<Task<T>> getDataAsync) 224 { 225 if (timeoutSeconds == 0) return await getDataAsync(); 226 var cacheValue = await GetAsync(key); 227 if (cacheValue != null) 228 { 229 try 230 { 231 return this.DeserializeObject<T>(cacheValue); 232 } 233 catch 234 { 235 await DelAsync(key); 236 throw; 237 } 238 } 239 var ret = await getDataAsync(); 240 await SetAsync(key, this.SerializeObject(ret), timeoutSeconds); 241 return ret; 242 } 243 /// <summary> 244 /// 缓存壳(哈希表) 245 /// </summary> 246 /// <typeparam name="T">缓存类型</typeparam> 247 /// <param name="key">不含prefix前辍</param> 248 /// <param name="field">字段</param> 249 /// <param name="timeoutSeconds">缓存秒数</param> 250 /// <param name="getDataAsync">获取源数据的函数</param> 251 /// <returns></returns> 252 async public Task<T> CacheShellAsync<T>(string key, string field, int timeoutSeconds, Func<Task<T>> getDataAsync) 253 { 254 if (timeoutSeconds == 0) return await getDataAsync(); 255 var cacheValue = await HGetAsync(key, field); 256 if (cacheValue != null) 257 { 258 try 259 { 260 var value = this.DeserializeObject<(T, long)>(cacheValue); 261 if (DateTime.Now.Subtract(_dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1; 262 } 263 catch 264 { 265 await HDelAsync(key, field); 266 throw; 267 } 268 } 269 var ret = await getDataAsync(); 270 await HSetAsync(key, field, this.SerializeObject((ret, (long)DateTime.Now.Subtract(_dt1970).TotalSeconds))); 271 return ret; 272 } 273 /// <summary> 274 /// 缓存壳(哈希表),将 fields 每个元素存储到单独的缓存片,实现最大化复用 275 /// </summary> 276 /// <typeparam name="T">缓存类型</typeparam> 277 /// <param name="key">不含prefix前辍</param> 278 /// <param name="fields">字段</param> 279 /// <param name="timeoutSeconds">缓存秒数</param> 280 /// <param name="getDataAsync">获取源数据的函数,输入参数是没有缓存的 fields,返回值应该是 (field, value)[]</param> 281 /// <returns></returns> 282 async public Task<(string key, T value)[]> CacheShellAsync<T>(string key, string[] fields, int timeoutSeconds, Func<string[], Task<(string, T)[]>> getDataAsync) 283 { 284 fields = fields?.Distinct().ToArray(); 285 if (fields == null || fields.Length == 0) return new (string, T)[0]; 286 if (timeoutSeconds == 0) return await getDataAsync(fields); 287 288 var ret = new (string, T)[fields.Length]; 289 var cacheValue = await HMGetAsync(key, fields); 290 var fieldsMGet = new Dictionary<string, int>(); 291 292 for (var a = 0; a < ret.Length; a++) 293 { 294 if (cacheValue[a] != null) 295 { 296 try 297 { 298 var value = this.DeserializeObject<(T, long)>(cacheValue[a]); 299 if (DateTime.Now.Subtract(_dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) 300 { 301 ret[a] = (fields[a], value.Item1); 302 continue; 303 } 304 } 305 catch 306 { 307 await HDelAsync(key, fields[a]); 308 throw; 309 } 310 } 311 fieldsMGet.Add(fields[a], a); 312 } 313 314 if (fieldsMGet.Any()) 315 { 316 var getDataIntput = fieldsMGet.Keys.ToArray(); 317 var data = await getDataAsync(getDataIntput); 318 var mset = new object[fieldsMGet.Count * 2]; 319 var msetIndex = 0; 320 foreach (var d in data) 321 { 322 if (fieldsMGet.ContainsKey(d.Item1) == false) throw new Exception($"使用 CacheShell 请确认 getData 返回值 (string, T)[] 中的 Item1 值: {d.Item1} 存在于 输入参数: {string.Join(",", getDataIntput)}"); 323 ret[fieldsMGet[d.Item1]] = d; 324 mset[msetIndex++] = d.Item1; 325 mset[msetIndex++] = this.SerializeObject((d.Item2, (long)DateTime.Now.Subtract(_dt1970).TotalSeconds)); 326 fieldsMGet.Remove(d.Item1); 327 } 328 foreach (var fieldNull in fieldsMGet.Keys) 329 { 330 ret[fieldsMGet[fieldNull]] = (fieldNull, default(T)); 331 mset[msetIndex++] = fieldNull; 332 mset[msetIndex++] = this.SerializeObject((default(T), (long)DateTime.Now.Subtract(_dt1970).TotalSeconds)); 333 } 334 if (mset.Any()) await HMSetAsync(key, mset); 335 } 336 return ret; 337 } 338 #endregion 339 340 #region 分区方式 ExecuteAsync 341 async private Task<T> ExecuteScalarAsync<T>(string key, Func<Object<RedisClient>, string, Task<T>> handerAsync) 342 { 343 if (key == null) return default(T); 344 var pool = NodeRuleRaw == null || Nodes.Count == 1 ? Nodes.First().Value : (Nodes.TryGetValue(NodeRuleRaw(key), out var b) ? b : Nodes.First().Value); 345 key = string.Concat(pool.Prefix, key); 346 return await GetAndExecuteAsync(pool, conn => handerAsync(conn, key)); 347 } 348 async private Task<T[]> ExecuteArrayAsync<T>(string[] key, Func<Object<RedisClient>, string[], Task<T[]>> handerAsync) 349 { 350 if (key == null || key.Any() == false) return new T[0]; 351 if (NodeRuleRaw == null || Nodes.Count == 1) 352 { 353 var pool = Nodes.First().Value; 354 var keys = key.Select(a => string.Concat(pool.Prefix, a)).ToArray(); 355 return await GetAndExecuteAsync(pool, conn => handerAsync(conn, keys)); 356 } 357 var rules = new Dictionary<string, List<(string, int)>>(); 358 for (var a = 0; a < key.Length; a++) 359 { 360 var rule = NodeRuleRaw(key[a]); 361 if (rules.ContainsKey(rule)) rules[rule].Add((key[a], a)); 362 else rules.Add(rule, new List<(string, int)> { (key[a], a) }); 363 } 364 T[] ret = new T[key.Length]; 365 foreach (var r in rules) 366 { 367 var pool = Nodes.TryGetValue(r.Key, out var b) ? b : Nodes.First().Value; 368 var keys = r.Value.Select(a => string.Concat(pool.Prefix, a.Item1)).ToArray(); 369 await GetAndExecuteAsync(pool, async conn => 370 { 371 var vals = await handerAsync(conn, keys); 372 for (var z = 0; z < r.Value.Count; z++) 373 { 374 ret[r.Value[z].Item2] = vals == null || z >= vals.Length ? default(T) : vals[z]; 375 } 376 return 0; 377 }); 378 } 379 return ret; 380 } 381 async private Task<long> ExecuteNonQueryAsync(string[] key, Func<Object<RedisClient>, string[], Task<long>> handerAsync) 382 { 383 if (key == null || key.Any() == false) return 0; 384 if (NodeRuleRaw == null || Nodes.Count == 1) 385 { 386 var pool = Nodes.First().Value; 387 var keys = key.Select(a => string.Concat(pool.Prefix, a)).ToArray(); 388 return await GetAndExecuteAsync(pool, conn => handerAsync(conn, keys)); 389 } 390 var rules = new Dictionary<string, List<string>>(); 391 for (var a = 0; a < key.Length; a++) 392 { 393 var rule = NodeRuleRaw(key[a]); 394 if (rules.ContainsKey(rule)) rules[rule].Add(key[a]); 395 else rules.Add(rule, new List<string> { key[a] }); 396 } 397 long affrows = 0; 398 foreach (var r in rules) 399 { 400 var pool = Nodes.TryGetValue(r.Key, out var b) ? b : Nodes.First().Value; 401 var keys = r.Value.Select(a => string.Concat(pool.Prefix, a)).ToArray(); 402 affrows += await GetAndExecuteAsync(pool, conn => handerAsync(conn, keys)); 403 } 404 return affrows; 405 } 406 #endregion 407 408 #region 服务器命令 409 public partial class NodesServerManagerProvider 410 { 411 412 async Task<(string node, T value)[]> NodesInternalAsync<T>(Func<Object<RedisClient>, Task<T>> handleAsync) 413 { 414 var ret = new List<(string, T)>(); 415 foreach (var pool in _csredis.Nodes.Values) 416 ret.Add((pool.Key, await _csredis.GetAndExecuteAsync(pool, c => handleAsync(c)))); 417 return ret.ToArray(); 418 } 419 420 /// <summary> 421 /// 异步执行一个 AOF(AppendOnly File) 文件重写操作 422 /// </summary> 423 /// <returns></returns> 424 public Task<(string node, string value)[]> BgRewriteAofAsync() => NodesInternalAsync(c => c.Value.BgRewriteAofAsync()); 425 /// <summary> 426 /// 在后台异步保存当前数据库的数据到磁盘 427 /// </summary> 428 /// <returns></returns> 429 public Task<(string node, string value)[]> BgSaveAsync() => NodesInternalAsync(c => c.Value.BgSaveAsync()); 430 /// <summary> 431 /// 关闭客户端连接 432 /// </summary> 433 /// <param name="ip">ip</param> 434 /// <param name="port">端口</param> 435 /// <returns></returns> 436 public Task<(string node, string value)[]> ClientKillAsync(string ip, int port) => NodesInternalAsync(c => c.Value.ClientKillAsync(ip, port)); 437 /// <summary> 438 /// 关闭客户端连接 439 /// </summary> 440 /// <param name="addr">ip:port</param> 441 /// <param name="id">客户唯一标识</param> 442 /// <param name="type">类型:normal | slave | pubsub</param> 443 /// <param name="skipMe">跳过自己</param> 444 /// <returns></returns> 445 public Task<(string node, long value)[]> ClientKillAsync(string addr = null, string id = null, ClientKillType? type = null, bool? skipMe = null) => NodesInternalAsync(c => c.Value.ClientKillAsync(addr, id, type?.ToString(), skipMe)); 446 /// <summary> 447 /// 获取连接到服务器的客户端连接列表 448 /// </summary> 449 /// <returns></returns> 450 public Task<(string node, string value)[]> ClientListAsync() => NodesInternalAsync(c => c.Value.ClientListAsync()); 451 /// <summary> 452 /// 获取连接的名称 453 /// </summary> 454 /// <returns></returns> 455 public Task<(string node, string value)[]> ClientGetNameAsync() => NodesInternalAsync(c => c.Value.ClientGetNameAsync()); 456 /// <summary> 457 /// 在指定时间内终止运行来自客户端的命令 458 /// </summary> 459 /// <param name="timeout">阻塞时间</param> 460 /// <returns></returns> 461 public Task<(string node, string value)[]> ClientPauseAsync(TimeSpan timeout) => NodesInternalAsync(c => c.Value.ClientPauseAsync(timeout)); 462 /// <summary> 463 /// 设置当前连接的名称 464 /// </summary> 465 /// <param name="connectionName">连接名称</param> 466 /// <returns></returns> 467 public Task<(string node, string value)[]> ClientSetNameAsync(string connectionName) => NodesInternalAsync(c => c.Value.ClientSetNameAsync(connectionName)); 468 /// <summary> 469 /// 返回当前服务器时间 470 /// </summary> 471 /// <returns></returns> 472 public Task<(string node, DateTime value)[]> TimeAsync() => NodesInternalAsync(c => c.Value.TimeAsync()); 473 /// <summary> 474 /// 获取指定配置参数的值 475 /// </summary> 476 /// <param name="parameter">参数</param> 477 /// <returns></returns> 478 public Task<(string node, Dictionary<string, string> value)[]> ConfigGetAsync(string parameter) => NodesInternalAsync(async c => (await c.Value.ConfigGetAsync(parameter)).ToDictionary(z => z.Item1, y => y.Item2)); 479 /// <summary> 480 /// 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写 481 /// </summary> 482 /// <returns></returns> 483 public Task<(string node, string value)[]> ConfigRewriteAsync() => NodesInternalAsync(c => c.Value.ConfigRewriteAsync()); 484 /// <summary> 485 /// 修改 redis 配置参数,无需重启 486 /// </summary> 487 /// <param name="parameter">参数</param> 488 /// <param name="value">值</param> 489 /// <returns></returns> 490 public Task<(string node, string value)[]> ConfigSetAsync(string parameter, string value) => NodesInternalAsync(c => c.Value.ConfigSetAsync(parameter, value)); 491 /// <summary> 492 /// 重置 INFO 命令中的某些统计数据 493 /// </summary> 494 /// <returns></returns> 495 public Task<(string node, string value)[]> ConfigResetStatAsync() => NodesInternalAsync(c => c.Value.ConfigResetStatAsync()); 496 /// <summary> 497 /// 返回当前数据库的 key 的数量 498 /// </summary> 499 /// <returns></returns> 500 public Task<(string node, long value)[]> DbSizeAsync() => NodesInternalAsync(c => c.Value.DbSizeAsync()); 501 /// <summary> 502 /// 让 Redis 服务崩溃 503 /// </summary> 504 /// <returns></returns> 505 public Task<(string node, string value)[]> DebugSegFaultAsync() => NodesInternalAsync(c => c.Value.DebugSegFaultAsync()); 506 /// <summary> 507 /// 删除所有数据库的所有key 508 /// </summary> 509 /// <returns></returns> 510 public Task<(string node, string value)[]> FlushAllAsync() => NodesInternalAsync(c => c.Value.FlushAllAsync()); 511 /// <summary> 512 /// 删除当前数据库的所有key 513 /// </summary> 514 /// <returns></returns> 515 public Task<(string node, string value)[]> FlushDbAsync() => NodesInternalAsync(c => c.Value.FlushDbAsync()); 516 /// <summary> 517 /// 获取 Redis 服务器的各种信息和统计数值 518 /// </summary> 519 /// <param name="section">部分(all|default|server|clients|memory|persistence|stats|replication|cpu|commandstats|cluster|keyspace)</param> 520 /// <returns></returns> 521 public Task<(string node, string value)[]> InfoAsync(InfoSection? section = null) => NodesInternalAsync(c => c.Value.InfoAsync(section?.ToString())); 522 /// <summary> 523 /// 返回最近一次 Redis 成功将数据保存到磁盘上的时间 524 /// </summary> 525 /// <returns></returns> 526 public Task<(string node, DateTime value)[]> LastSaveAsync() => NodesInternalAsync(c => c.Value.LastSaveAsync()); 527 /// <summary> 528 /// 返回主从实例所属的角色 529 /// </summary> 530 /// <returns></returns> 531 public Task<(string node, RedisRole value)[]> RoleAsync() => NodesInternalAsync(c => c.Value.RoleAsync()); 532 /// <summary> 533 /// 同步保存数据到硬盘 534 /// </summary> 535 /// <returns></returns> 536 public Task<(string node, string value)[]> SaveAsync() => NodesInternalAsync(c => c.Value.SaveAsync()); 537 /// <summary> 538 /// 异步保存数据到硬盘,并关闭服务器 539 /// </summary> 540 /// <param name="isSave">是否保存</param> 541 /// <returns></returns> 542 public Task<(string node, string value)[]> ShutdownAsync(bool isSave = true) => NodesInternalAsync(c => c.Value.ShutdownAsync(isSave)); 543 /// <summary> 544 /// 将服务器转变为指定服务器的从属服务器(slave server),如果当前服务器已经是某个主服务器(master server)的从属服务器,那么执行 SLAVEOF host port 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步。 545 /// </summary> 546 /// <param name="host">主机</param> 547 /// <param name="port">端口</param> 548 /// <returns></returns> 549 public Task<(string node, string value)[]> SlaveOfAsync(string host, int port) => NodesInternalAsync(c => c.Value.SlaveOfAsync(host, port)); 550 /// <summary> 551 /// 从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。 552 /// </summary> 553 /// <returns></returns> 554 public Task<(string node, string value)[]> SlaveOfNoOneAsync() => NodesInternalAsync(c => c.Value.SlaveOfNoOneAsync()); 555 /// <summary> 556 /// 管理 redis 的慢日志,按数量获取 557 /// </summary> 558 /// <param name="count">数量</param> 559 /// <returns></returns> 560 public Task<(string node, RedisSlowLogEntry[] value)[]> SlowLogGetAsync(long? count = null) => NodesInternalAsync(c => c.Value.SlowLogGetAsync(count)); 561 /// <summary> 562 /// 管理 redis 的慢日志,总数量 563 /// </summary> 564 /// <returns></returns> 565 public Task<(string node, long value)[]> SlowLogLenAsync() => NodesInternalAsync(c => c.Value.SlowLogLenAsync()); 566 /// <summary> 567 /// 管理 redis 的慢日志,清空 568 /// </summary> 569 /// <returns></returns> 570 public Task<(string node, string value)[]> SlowLogResetAsync() => NodesInternalAsync(c => c.Value.SlowLogResetAsync()); 571 /// <summary> 572 /// 用于复制功能(replication)的内部命令 573 /// </summary> 574 /// <returns></returns> 575 public Task<(string node, byte[] value)[]> SyncAsync() => NodesInternalAsync(c => c.Value.SyncAsync()); 576 } 577 578 public partial class NodeServerManagerProvider 579 { 580 581 /// <summary> 582 /// 异步执行一个 AOF(AppendOnly File) 文件重写操作 583 /// </summary> 584 /// <returns></returns> 585 public Task<string> BgRewriteAofAsync() => _csredis.GetAndExecute(_pool, c => c.Value.BgRewriteAofAsync()); 586 /// <summary> 587 /// 在后台异步保存当前数据库的数据到磁盘 588 /// </summary> 589 /// <returns></returns> 590 public Task<string> BgSaveAsync() => _csredis.GetAndExecute(_pool, c => c.Value.BgSaveAsync()); 591 /// <summary> 592 /// 关闭客户端连接 593 /// </summary> 594 /// <param name="ip">ip</param> 595 /// <param name="port">端口</param> 596 /// <returns></returns> 597 public Task<string> ClientKillAsync(string ip, int port) => _csredis.GetAndExecute(_pool, c => c.Value.ClientKillAsync(ip, port)); 598 /// <summary> 599 /// 关闭客户端连接 600 /// </summary> 601 /// <param name="addr">ip:port</param> 602 /// <param name="id">客户唯一标识</param> 603 /// <param name="type">类型:normal | slave | pubsub</param> 604 /// <param name="skipMe">跳过自己</param> 605 /// <returns></returns> 606 public Task<long> ClientKillAsync(string addr = null, string id = null, ClientKillType? type = null, bool? skipMe = null) => _csredis.GetAndExecute(_pool, c => c.Value.ClientKillAsync(addr, id, type?.ToString(), skipMe)); 607 /// <summary> 608 /// 获取连接到服务器的客户端连接列表 609 /// </summary> 610 /// <returns></returns> 611 public Task<string> ClientListAsync() => _csredis.GetAndExecute(_pool, c => c.Value.ClientListAsync()); 612 /// <summary> 613 /// 获取连接的名称 614 /// </summary> 615 /// <returns></returns> 616 public Task<string> ClientGetNameAsync() => _csredis.GetAndExecute(_pool, c => c.Value.ClientGetNameAsync()); 617 /// <summary> 618 /// 在指定时间内终止运行来自客户端的命令 619 /// </summary> 620 /// <param name="timeout">阻塞时间</param> 621 /// <returns></returns> 622 public Task<string> ClientPauseAsync(TimeSpan timeout) => _csredis.GetAndExecute(_pool, c => c.Value.ClientPauseAsync(timeout)); 623 /// <summary> 624 /// 设置当前连接的名称 625 /// </summary> 626 /// <param name="connectionName">连接名称</param> 627 /// <returns></returns> 628 public Task<string> ClientSetNameAsync(string connectionName) => _csredis.GetAndExecute(_pool, c => c.Value.ClientSetNameAsync(connectionName)); 629 /// <summary> 630 /// 返回当前服务器时间 631 /// </summary> 632 /// <returns></returns> 633 public Task<DateTime> TimeAsync() => _csredis.GetAndExecute(_pool, c => c.Value.TimeAsync()); 634 /// <summary> 635 /// 获取指定配置参数的值 636 /// </summary> 637 /// <param name="parameter">参数</param> 638 /// <returns></returns> 639 async public Task<Dictionary<string, string>> ConfigGetAsync(string parameter) => (await _csredis.GetAndExecute(_pool, c => c.Value.ConfigGetAsync(parameter))).ToDictionary(z => z.Item1, y => y.Item2); 640 /// <summary> 641 /// 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写 642 /// </summary> 643 /// <returns></returns> 644 public Task<string> ConfigRewriteAsync() => _csredis.GetAndExecute(_pool, c => c.Value.ConfigRewriteAsync()); 645 /// <summary> 646 /// 修改 redis 配置参数,无需重启 647 /// </summary> 648 /// <param name="parameter">参数</param> 649 /// <param name="value">值</param> 650 /// <returns></returns> 651 public Task<string> ConfigSetAsync(string parameter, string value) => _csredis.GetAndExecute(_pool, c => c.Value.ConfigSetAsync(parameter, value)); 652 /// <summary> 653 /// 重置 INFO 命令中的某些统计数据 654 /// </summary> 655 /// <returns></returns> 656 public Task<string> ConfigResetStatAsync() => _csredis.GetAndExecute(_pool, c => c.Value.ConfigResetStatAsync()); 657 /// <summary> 658 /// 返回当前数据库的 key 的数量 659 /// </summary> 660 /// <returns></returns> 661 public Task<long> DbSizeAsync() => _csredis.GetAndExecute(_pool, c => c.Value.DbSizeAsync()); 662 /// <summary> 663 /// 让 Redis 服务崩溃 664 /// </summary> 665 /// <returns></returns> 666 public Task<string> DebugSegFaultAsync() => _csredis.GetAndExecute(_pool, c => c.Value.DebugSegFaultAsync()); 667 /// <summary> 668 /// 删除所有数据库的所有key 669 /// </summary> 670 /// <returns></returns> 671 public Task<string> FlushAllAsync() => _csredis.GetAndExecute(_pool, c => c.Value.FlushAllAsync()); 672 /// <summary> 673 /// 删除当前数据库的所有key 674 /// </summary> 675 /// <returns></returns> 676 public Task<string> FlushDbAsync() => _csredis.GetAndExecute(_pool, c => c.Value.FlushDbAsync()); 677 /// <summary> 678 /// 获取 Redis 服务器的各种信息和统计数值 679 /// </summary> 680 /// <param name="section">部分(Server | Clients | Memory | Persistence | Stats | Replication | CPU | Keyspace)</param> 681 /// <returns></returns> 682 public Task<string> InfoAsync(InfoSection? section = null) => _csredis.GetAndExecute(_pool, c => c.Value.InfoAsync(section?.ToString())); 683 /// <summary> 684 /// 返回最近一次 Redis 成功将数据保存到磁盘上的时间 685 /// </summary> 686 /// <returns></returns> 687 public Task<DateTime> LastSaveAsync() => _csredis.GetAndExecute(_pool, c => c.Value.LastSaveAsync()); 688 /// <summary> 689 /// 返回主从实例所属的角色 690 /// </summary> 691 /// <returns></returns> 692 public Task<RedisRole> RoleAsync() => _csredis.GetAndExecute(_pool, c => c.Value.RoleAsync()); 693 /// <summary> 694 /// 同步保存数据到硬盘 695 /// </summary> 696 /// <returns></returns> 697 public Task<string> SaveAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SaveAsync()); 698 /// <summary> 699 /// 异步保存数据到硬盘,并关闭服务器 700 /// </summary> 701 /// <param name="isSave">是否保存</param> 702 /// <returns></returns> 703 public Task<string> ShutdownAsync(bool isSave = true) => _csredis.GetAndExecute(_pool, c => c.Value.ShutdownAsync(isSave)); 704 /// <summary> 705 /// 将服务器转变为指定服务器的从属服务器(slave server),如果当前服务器已经是某个主服务器(master server)的从属服务器,那么执行 SLAVEOF host port 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步。 706 /// </summary> 707 /// <param name="host">主机</param> 708 /// <param name="port">端口</param> 709 /// <returns></returns> 710 public Task<string> SlaveOfAsync(string host, int port) => _csredis.GetAndExecute(_pool, c => c.Value.SlaveOfAsync(host, port)); 711 /// <summary> 712 /// 从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。 713 /// </summary> 714 /// <returns></returns> 715 public Task<string> SlaveOfNoOneAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SlaveOfNoOneAsync()); 716 /// <summary> 717 /// 管理 redis 的慢日志,按数量获取 718 /// </summary> 719 /// <param name="count">数量</param> 720 /// <returns></returns> 721 public Task<RedisSlowLogEntry[]> SlowLogGetAsync(long? count = null) => _csredis.GetAndExecute(_pool, c => c.Value.SlowLogGetAsync(count)); 722 /// <summary> 723 /// 管理 redis 的慢日志,总数量 724 /// </summary> 725 /// <returns></returns> 726 public Task<long> SlowLogLenAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SlowLogLenAsync()); 727 /// <summary> 728 /// 管理 redis 的慢日志,清空 729 /// </summary> 730 /// <returns></returns> 731 public Task<string> SlowLogResetAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SlowLogResetAsync()); 732 /// <summary> 733 /// 用于复制功能(replication)的内部命令 734 /// </summary> 735 /// <returns></returns> 736 public Task<byte[]> SyncAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SyncAsync()); 737 } 738 #endregion 739 740 #region 连接命令 741 /// <summary> 742 /// 验证密码是否正确 743 /// </summary> 744 /// <param name="nodeKey">分区key</param> 745 /// <param name="password">密码</param> 746 /// <returns></returns> 747 [Obsolete("不建议手工执行,连接池自己管理最佳")] 748 private Task<bool> AuthAsync(string nodeKey, string password) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), async c => await c.Value.AuthAsync(password) == "OK"); 749 /// <summary> 750 /// 打印字符串 751 /// </summary> 752 /// <param name="nodeKey">分区key</param> 753 /// <param name="message">消息</param> 754 /// <returns></returns> 755 public Task<string> EchoAsync(string nodeKey, string message) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), c => c.Value.EchoAsync(message)); 756 /// <summary> 757 /// 打印字符串 758 /// </summary> 759 /// <param name="message">消息</param> 760 /// <returns></returns> 761 public Task<string> EchoAsync(string message) => GetAndExecuteAsync(Nodes.First().Value, c => c.Value.EchoAsync(message)); 762 /// <summary> 763 /// 查看服务是否运行 764 /// </summary> 765 /// <param name="nodeKey">分区key</param> 766 /// <returns></returns> 767 public Task<bool> PingAsync(string nodeKey) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), async c => await c.Value.PingAsync() == "PONG"); 768 /// <summary> 769 /// 查看服务是否运行 770 /// </summary> 771 /// <returns></returns> 772 public Task<bool> PingAsync() => GetAndExecuteAsync(Nodes.First().Value, async c => await c.Value.PingAsync() == "PONG"); 773 /// <summary> 774 /// 关闭当前连接 775 /// </summary> 776 /// <param name="nodeKey">分区key</param> 777 /// <returns></returns> 778 [Obsolete("不建议手工执行,连接池自己管理最佳")] 779 private Task<bool> QuitAsync(string nodeKey) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), async c => await c.Value.QuitAsync() == "OK"); 780 /// <summary> 781 /// 切换到指定的数据库 782 /// </summary> 783 /// <param name="nodeKey">分区key</param> 784 /// <param name="index">数据库</param> 785 /// <returns></returns> 786 [Obsolete("不建议手工执行,连接池所有连接应该指向同一数据库,若手工修改将导致数据的不一致")] 787 private Task<bool> SelectAsync(string nodeKey, int index) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), async c => await c.Value.SelectAsync(index) == "OK"); 788 #endregion 789 790 #region Script 791 /// <summary> 792 /// 执行脚本 793 /// </summary> 794 /// <param name="script">Lua 脚本</param> 795 /// <param name="key">用于定位分区节点,不含prefix前辍</param> 796 /// <param name="args">参数</param> 797 /// <returns></returns> 798 public Task<object> EvalAsync(string script, string key, params object[] args) 799 { 800 var args2 = args?.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 801 return ExecuteScalarAsync(key, (c, k) => c.Value.EvalAsync(script, new[] { k }, args2)); 802 } 803 /// <summary> 804 /// 执行脚本 805 /// </summary> 806 /// <param name="sha1">脚本缓存的sha1</param> 807 /// <param name="key">用于定位分区节点,不含prefix前辍</param> 808 /// <param name="args">参数</param> 809 /// <returns></returns> 810 public Task<object> EvalSHAAsync(string sha1, string key, params object[] args) 811 { 812 var args2 = args?.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 813 return ExecuteScalarAsync(key, (c, k) => c.Value.EvalSHAAsync(sha1, new[] { k }, args2)); 814 } 815 /// <summary> 816 /// 校验所有分区节点中,脚本是否已经缓存。任何分区节点未缓存sha1,都返回false。 817 /// </summary> 818 /// <param name="sha1">脚本缓存的sha1</param> 819 /// <returns></returns> 820 async public Task<bool[]> ScriptExistsAsync(params string[] sha1) 821 { 822 var ret = new List<bool>(); 823 foreach (var pool in Nodes.Values) 824 ret.Add((await GetAndExecuteAsync(pool, c => c.Value.ScriptExistsAsync(sha1)))?.Where(z => z == false).Any() == false); 825 return ret.ToArray(); 826 } 827 /// <summary> 828 /// 清除所有分区节点中,所有 Lua 脚本缓存 829 /// </summary> 830 async public Task ScriptFlushAsync() 831 { 832 foreach (var pool in Nodes.Values) 833 await GetAndExecuteAsync(pool, c => c.Value.ScriptFlushAsync()); 834 } 835 /// <summary> 836 /// 杀死所有分区节点中,当前正在运行的 Lua 脚本 837 /// </summary> 838 async public Task ScriptKillAsync() 839 { 840 foreach (var pool in Nodes.Values) 841 await GetAndExecuteAsync(pool, c => c.Value.ScriptKillAsync()); 842 } 843 /// <summary> 844 /// 在所有分区节点中,缓存脚本后返回 sha1(同样的脚本在任何服务器,缓存后的 sha1 都是相同的) 845 /// </summary> 846 /// <param name="script">Lua 脚本</param> 847 /// <returns></returns> 848 async public Task<string> ScriptLoadAsync(string script) 849 { 850 string sha1 = null; 851 foreach (var pool in Nodes.Values) 852 sha1 = await GetAndExecuteAsync(pool, c => c.Value.ScriptLoadAsync(script)); 853 return sha1; 854 } 855 #endregion 856 857 #region Pub/Sub 858 /// <summary> 859 /// 用于将信息发送到指定分区节点的频道,最终消息发布格式:1|message 860 /// </summary> 861 /// <param name="channel">频道名</param> 862 /// <param name="message">消息文本</param> 863 /// <returns></returns> 864 async public Task<long> PublishAsync(string channel, string message) 865 { 866 var msgid = await HIncrByAsync("csredisclient:Publish:msgid", channel, 1); 867 return await ExecuteScalarAsync(channel, (c, k) => c.Value.PublishAsync(channel, $"{msgid}|{message}")); 868 } 869 /// <summary> 870 /// 用于将信息发送到指定分区节点的频道,与 Publish 方法不同,不返回消息id头,即 1| 871 /// </summary> 872 /// <param name="channel">频道名</param> 873 /// <param name="message">消息文本</param> 874 /// <returns></returns> 875 public Task<long> PublishNoneMessageIdAsync(string channel, string message) => ExecuteScalarAsync(channel, (c, k) => c.Value.PublishAsync(channel, message)); 876 /// <summary> 877 /// 查看所有订阅频道 878 /// </summary> 879 /// <param name="pattern"></param> 880 /// <returns></returns> 881 async public Task<string[]> PubSubChannelsAsync(string pattern) 882 { 883 var ret = new List<string>(); 884 foreach (var pool in Nodes.Values) 885 ret.AddRange(await GetAndExecuteAsync(pool, c => c.Value.PubSubChannelsAsync(pattern))); 886 return ret.ToArray(); 887 } 888 /// <summary> 889 /// 查看所有模糊订阅端的数量 890 /// </summary> 891 /// <returns></returns> 892 [Obsolete("分区模式下,其他客户端的模糊订阅可能不会返回")] 893 public Task<long> PubSubNumPatAsync() => GetAndExecuteAsync(Nodes.First().Value, c => c.Value.PubSubNumPatAsync()); 894 /// <summary> 895 /// 查看所有订阅端的数量 896 /// </summary> 897 /// <param name="channels">频道</param> 898 /// <returns></returns> 899 [Obsolete("分区模式下,其他客户端的订阅可能不会返回")] 900 async public Task<Dictionary<string, long>> PubSubNumSubAsync(params string[] channels) => (await ExecuteArrayAsync(channels, (c, k) => 901 { 902 var prefix = (c.Pool as RedisClientPool).Prefix; 903 return c.Value.PubSubNumSubAsync(k.Select(z => string.IsNullOrEmpty(prefix) == false && z.StartsWith(prefix) ? z.Substring(prefix.Length) : z).ToArray()); 904 })).ToDictionary(z => z.Item1, y => y.Item2); 905 #endregion 906 907 #region HyperLogLog 908 /// <summary> 909 /// 添加指定元素到 HyperLogLog 910 /// </summary> 911 /// <param name="key">不含prefix前辍</param> 912 /// <param name="elements">元素</param> 913 /// <returns></returns> 914 async public Task<bool> PfAddAsync<T>(string key, params T[] elements) 915 { 916 if (elements == null || elements.Any() == false) return false; 917 var args = elements.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 918 return await ExecuteScalarAsync(key, (c, k) => c.Value.PfAddAsync(k, args)); 919 } 920 /// <summary> 921 /// 返回给定 HyperLogLog 的基数估算值 922 /// </summary> 923 /// <param name="keys">不含prefix前辍</param> 924 /// <returns></returns> 925 [Obsolete("分区模式下,若keys分散在多个分区节点时,将报错")] 926 public Task<long> PfCountAsync(params string[] keys) => NodesNotSupportAsync(keys, 0, (c, k) => c.Value.PfCountAsync(k)); 927 /// <summary> 928 /// 将多个 HyperLogLog 合并为一个 HyperLogLog 929 /// </summary> 930 /// <param name="destKey">新的 HyperLogLog,不含prefix前辍</param> 931 /// <param name="sourceKeys">源 HyperLogLog,不含prefix前辍</param> 932 /// <returns></returns> 933 [Obsolete("分区模式下,若keys分散在多个分区节点时,将报错")] 934 public Task<bool> PfMergeAsync(string destKey, params string[] sourceKeys) => NodesNotSupportAsync(new[] { destKey }.Concat(sourceKeys).ToArray(), false, async (c, k) => await c.Value.PfMergeAsync(k.First(), k.Skip(1).ToArray()) == "OK"); 935 #endregion 936 937 #region Sorted Set 938 /// <summary> 939 /// [redis-server 5.0.0] 删除并返回有序集合key中的最多count个具有最高得分的成员。如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最高的元素将是第一个元素,然后是分数较低的元素。 940 /// </summary> 941 /// <param name="key">不含prefix前辍</param> 942 /// <param name="count">数量</param> 943 /// <returns></returns> 944 async public Task<(string member, decimal score)[]> ZPopMaxAsync(string key, long count) => (await ExecuteScalarAsync(key, (c, k) => c.Value.ZPopMaxAsync(k, count))).Select(a => (a.Item1, a.Item2)).ToArray(); 945 /// <summary> 946 /// [redis-server 5.0.0] 删除并返回有序集合key中的最多count个具有最高得分的成员。如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最高的元素将是第一个元素,然后是分数较低的元素。 947 /// </summary> 948 /// <param name="key">不含prefix前辍</param> 949 /// <param name="count">数量</param> 950 /// <returns></returns> 951 async public Task<(T member, decimal score)[]> ZPopMaxAsync<T>(string key, long count) => this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZPopMaxBytesAsync(k, count))); 952 /// <summary> 953 /// [redis-server 5.0.0] 删除并返回有序集合key中的最多count个具有最低得分的成员。如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最低的元素将是第一个元素,然后是分数较高的元素。 954 /// </summary> 955 /// <param name="key">不含prefix前辍</param> 956 /// <param name="count">数量</param> 957 /// <returns></returns> 958 async public Task<(string member, decimal score)[]> ZPopMinAsync(string key, long count) => (await ExecuteScalarAsync(key, (c, k) => c.Value.ZPopMinAsync(k, count))).Select(a => (a.Item1, a.Item2)).ToArray(); 959 /// <summary> 960 /// [redis-server 5.0.0] 删除并返回有序集合key中的最多count个具有最低得分的成员。如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最低的元素将是第一个元素,然后是分数较高的元素。 961 /// </summary> 962 /// <param name="key">不含prefix前辍</param> 963 /// <param name="count">数量</param> 964 /// <returns></returns> 965 async public Task<(T member, decimal score)[]> ZPopMinAsync<T>(string key, long count) => this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZPopMinBytesAsync(k, count))); 966 967 /// <summary> 968 /// 向有序集合添加一个或多个成员,或者更新已存在成员的分数 969 /// </summary> 970 /// <param name="key">不含prefix前辍</param> 971 /// <param name="scoreMembers">一个或多个成员分数</param> 972 /// <returns></returns> 973 async public Task<long> ZAddAsync(string key, params (decimal, object)[] scoreMembers) 974 { 975 if (scoreMembers == null || scoreMembers.Any() == false) return 0; 976 var args = scoreMembers.Select(a => new Tuple<decimal, object>(a.Item1, this.SerializeRedisValueInternal(a.Item2))).ToArray(); 977 return await ExecuteScalarAsync(key, (c, k) => c.Value.ZAddAsync(k, args)); 978 } 979 /// <summary> 980 /// 获取有序集合的成员数量 981 /// </summary> 982 /// <param name="key">不含prefix前辍</param> 983 /// <returns></returns> 984 public Task<long> ZCardAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ZCardAsync(k)); 985 /// <summary> 986 /// 计算在有序集合中指定区间分数的成员数量 987 /// </summary> 988 /// <param name="key">不含prefix前辍</param> 989 /// <param name="min">分数最小值 decimal.MinValue 1</param> 990 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 991 /// <returns></returns> 992 public Task<long> ZCountAsync(string key, decimal min, decimal max) => ExecuteScalarAsync(key, (c, k) => c.Value.ZCountAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString())); 993 /// <summary> 994 /// 计算在有序集合中指定区间分数的成员数量 995 /// </summary> 996 /// <param name="key">不含prefix前辍</param> 997 /// <param name="min">分数最小值 -inf (1 1</param> 998 /// <param name="max">分数最大值 +inf (10 10</param> 999 /// <returns></returns> 1000 public Task<long> ZCountAsync(string key, string min, string max) => ExecuteScalarAsync(key, (c, k) => c.Value.ZCountAsync(k, min, max)); 1001 /// <summary> 1002 /// 有序集合中对指定成员的分数加上增量 increment 1003 /// </summary> 1004 /// <param name="key">不含prefix前辍</param> 1005 /// <param name="member">成员</param> 1006 /// <param name="increment">增量值(默认=1)</param> 1007 /// <returns></returns> 1008 public Task<decimal> ZIncrByAsync(string key, string member, decimal increment = 1) 1009 { 1010 var args = this.SerializeRedisValueInternal(member); 1011 return ExecuteScalarAsync(key, (c, k) => c.Value.ZIncrByAsync(k, increment, args)); 1012 } 1013 1014 /// <summary> 1015 /// 计算给定的一个或多个有序集的交集,将结果集存储在新的有序集合 destination 中 1016 /// </summary> 1017 /// <param name="destination">新的有序集合,不含prefix前辍</param> 1018 /// <param name="weights">使用 WEIGHTS 选项,你可以为 每个 给定有序集 分别 指定一个乘法因子。如果没有指定 WEIGHTS 选项,乘法因子默认设置为 1 。</param> 1019 /// <param name="aggregate">Sum | Min | Max</param> 1020 /// <param name="keys">一个或多个有序集合,不含prefix前辍</param> 1021 /// <returns></returns> 1022 public Task<long> ZInterStoreAsync(string destination, decimal[] weights, RedisAggregate aggregate, params string[] keys) 1023 { 1024 if (keys == null || keys.Length == 0) throw new Exception("keys 参数不可为空"); 1025 if (weights != null && weights.Length != keys.Length) throw new Exception("weights 和 keys 参数长度必须相同"); 1026 return NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.ZInterStoreAsync(k.First(), weights, aggregate, k.Skip(1).ToArray())); 1027 } 1028 1029 /// <summary> 1030 /// 通过索引区间返回有序集合成指定区间内的成员 1031 /// </summary> 1032 /// <param name="key">不含prefix前辍</param> 1033 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1034 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1035 /// <returns></returns> 1036 public Task<string[]> ZRangeAsync(string key, long start, long stop) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeAsync(k, start, stop, false)); 1037 /// <summary> 1038 /// 通过索引区间返回有序集合成指定区间内的成员 1039 /// </summary> 1040 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1041 /// <param name="key">不含prefix前辍</param> 1042 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1043 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1044 /// <returns></returns> 1045 async public Task<T[]> ZRangeAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesAsync(k, start, stop, false))); 1046 /// <summary> 1047 /// 通过索引区间返回有序集合成指定区间内的成员和分数 1048 /// </summary> 1049 /// <param name="key">不含prefix前辍</param> 1050 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1051 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1052 /// <returns></returns> 1053 async public Task<(string member, decimal score)[]> ZRangeWithScoresAsync(string key, long start, long stop) => (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeWithScoresAsync(k, start, stop))).Select(a => (a.Item1, a.Item2)).ToArray(); 1054 /// <summary> 1055 /// 通过索引区间返回有序集合成指定区间内的成员和分数 1056 /// </summary> 1057 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1058 /// <param name="key">不含prefix前辍</param> 1059 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1060 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1061 /// <returns></returns> 1062 async public Task<(T member, decimal score)[]> ZRangeWithScoresAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesWithScoresAsync(k, start, stop))); 1063 1064 /// <summary> 1065 /// 通过分数返回有序集合指定区间内的成员 1066 /// </summary> 1067 /// <param name="key">不含prefix前辍</param> 1068 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1069 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1070 /// <param name="count">返回多少成员</param> 1071 /// <param name="offset">返回条件偏移位置</param> 1072 /// <returns></returns> 1073 public Task<string[]> ZRangeByScoreAsync(string key, decimal min, decimal max, long? count = null, long offset = 0) => 1074 ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByScoreAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString(), false, offset, count)); 1075 /// <summary> 1076 /// 通过分数返回有序集合指定区间内的成员 1077 /// </summary> 1078 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1079 /// <param name="key">不含prefix前辍</param> 1080 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1081 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1082 /// <param name="count">返回多少成员</param> 1083 /// <param name="offset">返回条件偏移位置</param> 1084 /// <returns></returns> 1085 async public Task<T[]> ZRangeByScoreAsync<T>(string key, decimal min, decimal max, long? count = null, long offset = 0) => 1086 this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByScoreAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString(), false, offset, count))); 1087 /// <summary> 1088 /// 通过分数返回有序集合指定区间内的成员 1089 /// </summary> 1090 /// <param name="key">不含prefix前辍</param> 1091 /// <param name="min">分数最小值 -inf (1 1</param> 1092 /// <param name="max">分数最大值 +inf (10 10</param> 1093 /// <param name="count">返回多少成员</param> 1094 /// <param name="offset">返回条件偏移位置</param> 1095 /// <returns></returns> 1096 public Task<string[]> ZRangeByScoreAsync(string key, string min, string max, long? count = null, long offset = 0) => 1097 ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByScoreAsync(k, min, max, false, offset, count)); 1098 /// <summary> 1099 /// 通过分数返回有序集合指定区间内的成员 1100 /// </summary> 1101 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1102 /// <param name="key">不含prefix前辍</param> 1103 /// <param name="min">分数最小值 -inf (1 1</param> 1104 /// <param name="max">分数最大值 +inf (10 10</param> 1105 /// <param name="count">返回多少成员</param> 1106 /// <param name="offset">返回条件偏移位置</param> 1107 /// <returns></returns> 1108 async public Task<T[]> ZRangeByScoreAsync<T>(string key, string min, string max, long? count = null, long offset = 0) => 1109 this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByScoreAsync(k, min, max, false, offset, count))); 1110 1111 /// <summary> 1112 /// 通过分数返回有序集合指定区间内的成员和分数 1113 /// </summary> 1114 /// <param name="key">不含prefix前辍</param> 1115 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1116 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1117 /// <param name="count">返回多少成员</param> 1118 /// <param name="offset">返回条件偏移位置</param> 1119 /// <returns></returns> 1120 async public Task<(string member, decimal score)[]> ZRangeByScoreWithScoresAsync(string key, decimal min, decimal max, long? count = null, long offset = 0) => 1121 (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByScoreWithScoresAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString(), offset, count))).Select(z => (z.Item1, z.Item2)).ToArray(); 1122 /// <summary> 1123 /// 通过分数返回有序集合指定区间内的成员和分数 1124 /// </summary> 1125 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1126 /// <param name="key">不含prefix前辍</param> 1127 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1128 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1129 /// <param name="count">返回多少成员</param> 1130 /// <param name="offset">返回条件偏移位置</param> 1131 /// <returns></returns> 1132 async public Task<(T member, decimal score)[]> ZRangeByScoreWithScoresAsync<T>(string key, decimal min, decimal max, long? count = null, long offset = 0) => 1133 this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByScoreWithScoresAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString(), offset, count))); 1134 /// <summary> 1135 /// 通过分数返回有序集合指定区间内的成员和分数 1136 /// </summary> 1137 /// <param name="key">不含prefix前辍</param> 1138 /// <param name="min">分数最小值 -inf (1 1</param> 1139 /// <param name="max">分数最大值 +inf (10 10</param> 1140 /// <param name="count">返回多少成员</param> 1141 /// <param name="offset">返回条件偏移位置</param> 1142 /// <returns></returns> 1143 async public Task<(string member, decimal score)[]> ZRangeByScoreWithScoresAsync(string key, string min, string max, long? count = null, long offset = 0) => 1144 (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByScoreWithScoresAsync(k, min, max, offset, count))).Select(z => (z.Item1, z.Item2)).ToArray(); 1145 /// <summary> 1146 /// 通过分数返回有序集合指定区间内的成员和分数 1147 /// </summary> 1148 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1149 /// <param name="key">不含prefix前辍</param> 1150 /// <param name="min">分数最小值 -inf (1 1</param> 1151 /// <param name="max">分数最大值 +inf (10 10</param> 1152 /// <param name="count">返回多少成员</param> 1153 /// <param name="offset">返回条件偏移位置</param> 1154 /// <returns></returns> 1155 async public Task<(T member, decimal score)[]> ZRangeByScoreWithScoresAsync<T>(string key, string min, string max, long? count = null, long offset = 0) => 1156 this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByScoreWithScoresAsync(k, min, max, offset, count))); 1157 1158 /// <summary> 1159 /// 返回有序集合中指定成员的索引 1160 /// </summary> 1161 /// <param name="key">不含prefix前辍</param> 1162 /// <param name="member">成员</param> 1163 /// <returns></returns> 1164 public Task<long?> ZRankAsync(string key, object member) 1165 { 1166 var args = this.SerializeRedisValueInternal(member); 1167 return ExecuteScalarAsync(key, (c, k) => c.Value.ZRankAsync(k, args)); 1168 } 1169 /// <summary> 1170 /// 移除有序集合中的一个或多个成员 1171 /// </summary> 1172 /// <param name="key">不含prefix前辍</param> 1173 /// <param name="member">一个或多个成员</param> 1174 /// <returns></returns> 1175 async public Task<long> ZRemAsync<T>(string key, params T[] member) 1176 { 1177 if (member == null || member.Any() == false) return 0; 1178 var args = member.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 1179 return await ExecuteScalarAsync(key, (c, k) => c.Value.ZRemAsync(k, args)); 1180 } 1181 /// <summary> 1182 /// 移除有序集合中给定的排名区间的所有成员 1183 /// </summary> 1184 /// <param name="key">不含prefix前辍</param> 1185 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1186 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1187 /// <returns></returns> 1188 public Task<long> ZRemRangeByRankAsync(string key, long start, long stop) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRemRangeByRankAsync(k, start, stop)); 1189 /// <summary> 1190 /// 移除有序集合中给定的分数区间的所有成员 1191 /// </summary> 1192 /// <param name="key">不含prefix前辍</param> 1193 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1194 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1195 /// <returns></returns> 1196 public Task<long> ZRemRangeByScoreAsync(string key, decimal min, decimal max) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRemRangeByScoreAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString())); 1197 /// <summary> 1198 /// 移除有序集合中给定的分数区间的所有成员 1199 /// </summary> 1200 /// <param name="key">不含prefix前辍</param> 1201 /// <param name="min">分数最小值 -inf (1 1</param> 1202 /// <param name="max">分数最大值 +inf (10 10</param> 1203 /// <returns></returns> 1204 public Task<long> ZRemRangeByScoreAsync(string key, string min, string max) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRemRangeByScoreAsync(k, min, max)); 1205 1206 /// <summary> 1207 /// 返回有序集中指定区间内的成员,通过索引,分数从高到底 1208 /// </summary> 1209 /// <param name="key">不含prefix前辍</param> 1210 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1211 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1212 /// <returns></returns> 1213 public Task<string[]> ZRevRangeAsync(string key, long start, long stop) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeAsync(k, start, stop, false)); 1214 /// <summary> 1215 /// 返回有序集中指定区间内的成员,通过索引,分数从高到底 1216 /// </summary> 1217 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1218 /// <param name="key">不含prefix前辍</param> 1219 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1220 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1221 /// <returns></returns> 1222 async public Task<T[]> ZRevRangeAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesAsync(k, start, stop, false))); 1223 /// <summary> 1224 /// 返回有序集中指定区间内的成员和分数,通过索引,分数从高到底 1225 /// </summary> 1226 /// <param name="key">不含prefix前辍</param> 1227 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1228 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1229 /// <returns></returns> 1230 async public Task<(string member, decimal score)[]> ZRevRangeWithScoresAsync(string key, long start, long stop) => (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeWithScoresAsync(k, start, stop))).Select(a => (a.Item1, a.Item2)).ToArray(); 1231 /// <summary> 1232 /// 返回有序集中指定区间内的成员和分数,通过索引,分数从高到底 1233 /// </summary> 1234 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1235 /// <param name="key">不含prefix前辍</param> 1236 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1237 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1238 /// <returns></returns> 1239 async public Task<(T member, decimal score)[]> ZRevRangeWithScoresAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesWithScoresAsync(k, start, stop))); 1240 1241 /// <summary> 1242 /// 返回有序集中指定分数区间内的成员,分数从高到低排序 1243 /// </summary> 1244 /// <param name="key">不含prefix前辍</param> 1245 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1246 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1247 /// <param name="count">返回多少成员</param> 1248 /// <param name="offset">返回条件偏移位置</param> 1249 /// <returns></returns> 1250 public Task<string[]> ZRevRangeByScoreAsync(string key, decimal max, decimal min, long? count = null, long? offset = 0) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeByScoreAsync(k, max == decimal.MaxValue ? "+inf" : max.ToString(), min == decimal.MinValue ? "-inf" : min.ToString(), false, offset, count)); 1251 /// <summary> 1252 /// 返回有序集中指定分数区间内的成员,分数从高到低排序 1253 /// </summary> 1254 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1255 /// <param name="key">不含prefix前辍</param> 1256 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1257 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1258 /// <param name="count">返回多少成员</param> 1259 /// <param name="offset">返回条件偏移位置</param> 1260 /// <returns></returns> 1261 async public Task<T[]> ZRevRangeByScoreAsync<T>(string key, decimal max, decimal min, long? count = null, long offset = 0) => 1262 this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesByScoreAsync(k, max == decimal.MaxValue ? "+inf" : max.ToString(), min == decimal.MinValue ? "-inf" : min.ToString(), false, offset, count))); 1263 /// <summary> 1264 /// 返回有序集中指定分数区间内的成员,分数从高到低排序 1265 /// </summary> 1266 /// <param name="key">不含prefix前辍</param> 1267 /// <param name="max">分数最大值 +inf (10 10</param> 1268 /// <param name="min">分数最小值 -inf (1 1</param> 1269 /// <param name="count">返回多少成员</param> 1270 /// <param name="offset">返回条件偏移位置</param> 1271 /// <returns></returns> 1272 public Task<string[]> ZRevRangeByScoreAsync(string key, string max, string min, long? count = null, long? offset = 0) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeByScoreAsync(k, max, min, false, offset, count)); 1273 /// <summary> 1274 /// 返回有序集中指定分数区间内的成员,分数从高到低排序 1275 /// </summary> 1276 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1277 /// <param name="key">不含prefix前辍</param> 1278 /// <param name="max">分数最大值 +inf (10 10</param> 1279 /// <param name="min">分数最小值 -inf (1 1</param> 1280 /// <param name="count">返回多少成员</param> 1281 /// <param name="offset">返回条件偏移位置</param> 1282 /// <returns></returns> 1283 async public Task<T[]> ZRevRangeByScoreAsync<T>(string key, string max, string min, long? count = null, long offset = 0) => 1284 this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesByScoreAsync(k, max, min, false, offset, count))); 1285 1286 /// <summary> 1287 /// 返回有序集中指定分数区间内的成员和分数,分数从高到低排序 1288 /// </summary> 1289 /// <param name="key">不含prefix前辍</param> 1290 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1291 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1292 /// <param name="count">返回多少成员</param> 1293 /// <param name="offset">返回条件偏移位置</param> 1294 /// <returns></returns> 1295 async public Task<(string member, decimal score)[]> ZRevRangeByScoreWithScoresAsync(string key, decimal max, decimal min, long? count = null, long offset = 0) => 1296 (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeByScoreWithScoresAsync(k, max == decimal.MaxValue ? "+inf" : max.ToString(), min == decimal.MinValue ? "-inf" : min.ToString(), offset, count))).Select(z => (z.Item1, z.Item2)).ToArray(); 1297 /// <summary> 1298 /// 返回有序集中指定分数区间内的成员和分数,分数从高到低排序 1299 /// </summary> 1300 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1301 /// <param name="key">不含prefix前辍</param> 1302 /// <param name="max">分数最大值 decimal.MaxValue 10</param> 1303 /// <param name="min">分数最小值 decimal.MinValue 1</param> 1304 /// <param name="count">返回多少成员</param> 1305 /// <param name="offset">返回条件偏移位置</param> 1306 /// <returns></returns> 1307 async public Task<(T member, decimal score)[]> ZRevRangeByScoreWithScoresAsync<T>(string key, decimal max, decimal min, long? count = null, long offset = 0) => 1308 this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesByScoreWithScoresAsync(k, max == decimal.MaxValue ? "+inf" : max.ToString(), min == decimal.MinValue ? "-inf" : min.ToString(), offset, count))); 1309 /// <summary> 1310 /// 返回有序集中指定分数区间内的成员和分数,分数从高到低排序 1311 /// </summary> 1312 /// <param name="key">不含prefix前辍</param> 1313 /// <param name="max">分数最大值 +inf (10 10</param> 1314 /// <param name="min">分数最小值 -inf (1 1</param> 1315 /// <param name="count">返回多少成员</param> 1316 /// <param name="offset">返回条件偏移位置</param> 1317 /// <returns></returns> 1318 async public Task<(string member, decimal score)[]> ZRevRangeByScoreWithScoresAsync(string key, string max, string min, long? count = null, long offset = 0) => 1319 (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeByScoreWithScoresAsync(k, max, min, offset, count))).Select(z => (z.Item1, z.Item2)).ToArray(); 1320 /// <summary> 1321 /// 返回有序集中指定分数区间内的成员和分数,分数从高到低排序 1322 /// </summary> 1323 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1324 /// <param name="key">不含prefix前辍</param> 1325 /// <param name="max">分数最大值 +inf (10 10</param> 1326 /// <param name="min">分数最小值 -inf (1 1</param> 1327 /// <param name="count">返回多少成员</param> 1328 /// <param name="offset">返回条件偏移位置</param> 1329 /// <returns></returns> 1330 async public Task<(T member, decimal score)[]> ZRevRangeByScoreWithScoresAsync<T>(string key, string max, string min, long? count = null, long offset = 0) => 1331 this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesByScoreWithScoresAsync(k, max, min, offset, count))); 1332 1333 /// <summary> 1334 /// 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 1335 /// </summary> 1336 /// <param name="key">不含prefix前辍</param> 1337 /// <param name="member">成员</param> 1338 /// <returns></returns> 1339 public Task<long?> ZRevRankAsync(string key, object member) 1340 { 1341 var args = this.SerializeRedisValueInternal(member); 1342 return ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRankAsync(k, args)); 1343 } 1344 /// <summary> 1345 /// 返回有序集中,成员的分数值 1346 /// </summary> 1347 /// <param name="key">不含prefix前辍</param> 1348 /// <param name="member">成员</param> 1349 /// <returns></returns> 1350 public Task<decimal?> ZScoreAsync(string key, object member) 1351 { 1352 var args = this.SerializeRedisValueInternal(member); 1353 return ExecuteScalarAsync(key, (c, k) => c.Value.ZScoreAsync(k, args)); 1354 } 1355 1356 /// <summary> 1357 /// 计算给定的一个或多个有序集的并集,将结果集存储在新的有序集合 destination 中 1358 /// </summary> 1359 /// <param name="destination">新的有序集合,不含prefix前辍</param> 1360 /// <param name="weights">使用 WEIGHTS 选项,你可以为 每个 给定有序集 分别 指定一个乘法因子。如果没有指定 WEIGHTS 选项,乘法因子默认设置为 1 。</param> 1361 /// <param name="aggregate">Sum | Min | Max</param> 1362 /// <param name="keys">一个或多个有序集合,不含prefix前辍</param> 1363 /// <returns></returns> 1364 public Task<long> ZUnionStoreAsync(string destination, decimal[] weights, RedisAggregate aggregate, params string[] keys) 1365 { 1366 if (keys == null || keys.Length == 0) throw new Exception("keys 参数不可为空"); 1367 if (weights != null && weights.Length != keys.Length) throw new Exception("weights 和 keys 参数长度必须相同"); 1368 return NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.ZUnionStoreAsync(k.First(), weights, aggregate, k.Skip(1).ToArray())); 1369 } 1370 1371 /// <summary> 1372 /// 迭代有序集合中的元素 1373 /// </summary> 1374 /// <param name="key">不含prefix前辍</param> 1375 /// <param name="cursor">位置</param> 1376 /// <param name="pattern">模式</param> 1377 /// <param name="count">数量</param> 1378 /// <returns></returns> 1379 async public Task<RedisScan<(string member, decimal score)>> ZScanAsync(string key, long cursor, string pattern = null, long? count = null) 1380 { 1381 var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.ZScanAsync(k, cursor, pattern, count)); 1382 return new RedisScan<(string, decimal)>(scan.Cursor, scan.Items.Select(z => (z.Item1, z.Item2)).ToArray()); 1383 } 1384 /// <summary> 1385 /// 迭代有序集合中的元素 1386 /// </summary> 1387 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1388 /// <param name="key">不含prefix前辍</param> 1389 /// <param name="cursor">位置</param> 1390 /// <param name="pattern">模式</param> 1391 /// <param name="count">数量</param> 1392 /// <returns></returns> 1393 async public Task<RedisScan<(T member, decimal score)>> ZScanAsync<T>(string key, long cursor, string pattern = null, long? count = null) 1394 { 1395 var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.ZScanBytesAsync(k, cursor, pattern, count)); 1396 return new RedisScan<(T, decimal)>(scan.Cursor, this.DeserializeRedisValueTuple1Internal<T, decimal>(scan.Items)); 1397 } 1398 1399 /// <summary> 1400 /// 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的字典序来进行排序,这个命令可以返回给定的有序集合键 key 中,值介于 min 和 max 之间的成员。 1401 /// </summary> 1402 /// <param name="key">不含prefix前辍</param> 1403 /// <param name="min">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param> 1404 /// <param name="max">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param> 1405 /// <param name="count">返回多少成员</param> 1406 /// <param name="offset">返回条件偏移位置</param> 1407 /// <returns></returns> 1408 public Task<string[]> ZRangeByLexAsync(string key, string min, string max, long? count = null, long offset = 0) => 1409 ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByLexAsync(k, min, max, offset, count)); 1410 /// <summary> 1411 /// 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的字典序来进行排序,这个命令可以返回给定的有序集合键 key 中,值介于 min 和 max 之间的成员。 1412 /// </summary> 1413 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1414 /// <param name="key">不含prefix前辍</param> 1415 /// <param name="min">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param> 1416 /// <param name="max">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param> 1417 /// <param name="count">返回多少成员</param> 1418 /// <param name="offset">返回条件偏移位置</param> 1419 /// <returns></returns> 1420 async public Task<T[]> ZRangeByLexAsync<T>(string key, string min, string max, long? count = null, long offset = 0) => 1421 this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByLexAsync(k, min, max, offset, count))); 1422 1423 /// <summary> 1424 /// 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的字典序来进行排序,这个命令可以返回给定的有序集合键 key 中,值介于 min 和 max 之间的成员。 1425 /// </summary> 1426 /// <param name="key">不含prefix前辍</param> 1427 /// <param name="min">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param> 1428 /// <param name="max">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param> 1429 /// <returns></returns> 1430 public Task<long> ZRemRangeByLexAsync(string key, string min, string max) => 1431 ExecuteScalarAsync(key, (c, k) => c.Value.ZRemRangeByLexAsync(k, min, max)); 1432 /// <summary> 1433 /// 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的字典序来进行排序,这个命令可以返回给定的有序集合键 key 中,值介于 min 和 max 之间的成员。 1434 /// </summary> 1435 /// <param name="key">不含prefix前辍</param> 1436 /// <param name="min">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param> 1437 /// <param name="max">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param> 1438 /// <returns></returns> 1439 public Task<long> ZLexCountAsync(string key, string min, string max) => 1440 ExecuteScalarAsync(key, (c, k) => c.Value.ZLexCountAsync(k, min, max)); 1441 #endregion 1442 1443 #region Set 1444 /// <summary> 1445 /// 向集合添加一个或多个成员 1446 /// </summary> 1447 /// <param name="key">不含prefix前辍</param> 1448 /// <param name="members">一个或多个成员</param> 1449 /// <returns></returns> 1450 async public Task<long> SAddAsync<T>(string key, params T[] members) 1451 { 1452 if (members == null || members.Any() == false) return 0; 1453 var args = members.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 1454 return await ExecuteScalarAsync(key, (c, k) => c.Value.SAddAsync(k, args)); 1455 } 1456 /// <summary> 1457 /// 获取集合的成员数 1458 /// </summary> 1459 /// <param name="key">不含prefix前辍</param> 1460 /// <returns></returns> 1461 public Task<long> SCardAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.SCardAsync(k)); 1462 /// <summary> 1463 /// 返回给定所有集合的差集 1464 /// </summary> 1465 /// <param name="keys">不含prefix前辍</param> 1466 /// <returns></returns> 1467 public Task<string[]> SDiffAsync(params string[] keys) => NodesNotSupportAsync(keys, new string[0], (c, k) => c.Value.SDiffAsync(k)); 1468 /// <summary> 1469 /// 返回给定所有集合的差集 1470 /// </summary> 1471 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1472 /// <param name="keys">不含prefix前辍</param> 1473 /// <returns></returns> 1474 async public Task<T[]> SDiffAsync<T>(params string[] keys) => this.DeserializeRedisValueArrayInternal<T>(await NodesNotSupportAsync(keys, new byte[0][], (c, k) => c.Value.SDiffBytesAsync(k))); 1475 /// <summary> 1476 /// 返回给定所有集合的差集并存储在 destination 中 1477 /// </summary> 1478 /// <param name="destination">新的无序集合,不含prefix前辍</param> 1479 /// <param name="keys">一个或多个无序集合,不含prefix前辍</param> 1480 /// <returns></returns> 1481 public Task<long> SDiffStoreAsync(string destination, params string[] keys) => NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.SDiffStoreAsync(k.First(), k.Skip(1).ToArray())); 1482 /// <summary> 1483 /// 返回给定所有集合的交集 1484 /// </summary> 1485 /// <param name="keys">不含prefix前辍</param> 1486 /// <returns></returns> 1487 public Task<string[]> SInterAsync(params string[] keys) => NodesNotSupportAsync(keys, new string[0], (c, k) => c.Value.SInterAsync(k)); 1488 /// <summary> 1489 /// 返回给定所有集合的交集 1490 /// </summary> 1491 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1492 /// <param name="keys">不含prefix前辍</param> 1493 /// <returns></returns> 1494 async public Task<T[]> SInterAsync<T>(params string[] keys) => this.DeserializeRedisValueArrayInternal<T>(await NodesNotSupportAsync(keys, new byte[0][], (c, k) => c.Value.SInterBytesAsync(k))); 1495 /// <summary> 1496 /// 返回给定所有集合的交集并存储在 destination 中 1497 /// </summary> 1498 /// <param name="destination">新的无序集合,不含prefix前辍</param> 1499 /// <param name="keys">一个或多个无序集合,不含prefix前辍</param> 1500 /// <returns></returns> 1501 public Task<long> SInterStoreAsync(string destination, params string[] keys) => NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.SInterStoreAsync(k.First(), k.Skip(1).ToArray())); 1502 /// <summary> 1503 /// 判断 member 元素是否是集合 key 的成员 1504 /// </summary> 1505 /// <param name="key">不含prefix前辍</param> 1506 /// <param name="member">成员</param> 1507 /// <returns></returns> 1508 public Task<bool> SIsMemberAsync(string key, object member) 1509 { 1510 var args = this.SerializeRedisValueInternal(member); 1511 return ExecuteScalarAsync(key, (c, k) => c.Value.SIsMemberAsync(k, args)); 1512 } 1513 /// <summary> 1514 /// 返回集合中的所有成员 1515 /// </summary> 1516 /// <param name="key">不含prefix前辍</param> 1517 /// <returns></returns> 1518 public Task<string[]> SMembersAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.SMembersAsync(k)); 1519 /// <summary> 1520 /// 返回集合中的所有成员 1521 /// </summary> 1522 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1523 /// <param name="key">不含prefix前辍</param> 1524 /// <returns></returns> 1525 async public Task<T[]> SMembersAsync<T>(string key) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SMembersBytesAsync(k))); 1526 /// <summary> 1527 /// 将 member 元素从 source 集合移动到 destination 集合 1528 /// </summary> 1529 /// <param name="source">无序集合key,不含prefix前辍</param> 1530 /// <param name="destination">目标无序集合key,不含prefix前辍</param> 1531 /// <param name="member">成员</param> 1532 /// <returns></returns> 1533 async public Task<bool> SMoveAsync(string source, string destination, object member) 1534 { 1535 string rule = string.Empty; 1536 if (Nodes.Count > 1) 1537 { 1538 var rule1 = NodeRuleRaw(source); 1539 var rule2 = NodeRuleRaw(destination); 1540 if (rule1 != rule2) 1541 { 1542 if (await SRemAsync(source, member) <= 0) return false; 1543 return await SAddAsync(destination, member) > 0; 1544 } 1545 rule = rule1; 1546 } 1547 var pool = Nodes.TryGetValue(rule, out var b) ? b : Nodes.First().Value; 1548 var key1 = string.Concat(pool.Prefix, source); 1549 var key2 = string.Concat(pool.Prefix, destination); 1550 var args = this.SerializeRedisValueInternal(member); 1551 return await GetAndExecuteAsync(pool, conn => conn.Value.SMoveAsync(key1, key2, args)); 1552 } 1553 /// <summary> 1554 /// 移除并返回集合中的一个随机元素 1555 /// </summary> 1556 /// <param name="key">不含prefix前辍</param> 1557 /// <returns></returns> 1558 public Task<string> SPopAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.SPopAsync(k)); 1559 /// <summary> 1560 /// 移除并返回集合中的一个随机元素 1561 /// </summary> 1562 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1563 /// <param name="key">不含prefix前辍</param> 1564 /// <returns></returns> 1565 async public Task<T> SPopAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SPopBytesAsync(k))); 1566 /// <summary> 1567 /// [redis-server 3.2] 移除并返回集合中的一个或多个随机元素 1568 /// </summary> 1569 /// <param name="key">不含prefix前辍</param> 1570 /// <param name="count">移除并返回的个数</param> 1571 /// <returns></returns> 1572 public Task<string[]> SPopAsync(string key, long count) => ExecuteScalarAsync(key, (c, k) => c.Value.SPopAsync(k, count)); 1573 /// <summary> 1574 /// [redis-server 3.2] 移除并返回集合中的一个或多个随机元素 1575 /// </summary> 1576 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1577 /// <param name="key">不含prefix前辍</param> 1578 /// <param name="count">移除并返回的个数</param> 1579 /// <returns></returns> 1580 async public Task<T[]> SPopAsync<T>(string key, long count) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SPopBytesAsync(k, count))); 1581 /// <summary> 1582 /// 返回集合中的一个随机元素 1583 /// </summary> 1584 /// <param name="key">不含prefix前辍</param> 1585 /// <returns></returns> 1586 public Task<string> SRandMemberAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.SRandMemberAsync(k)); 1587 /// <summary> 1588 /// 返回集合中的一个随机元素 1589 /// </summary> 1590 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1591 /// <param name="key">不含prefix前辍</param> 1592 /// <returns></returns> 1593 async public Task<T> SRandMemberAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SRandMemberBytesAsync(k))); 1594 /// <summary> 1595 /// 返回集合中一个或多个随机数的元素 1596 /// </summary> 1597 /// <param name="key">不含prefix前辍</param> 1598 /// <param name="count">返回个数</param> 1599 /// <returns></returns> 1600 public Task<string[]> SRandMembersAsync(string key, int count = 1) => ExecuteScalarAsync(key, (c, k) => c.Value.SRandMembersAsync(k, count)); 1601 /// <summary> 1602 /// 返回集合中一个或多个随机数的元素 1603 /// </summary> 1604 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1605 /// <param name="key">不含prefix前辍</param> 1606 /// <param name="count">返回个数</param> 1607 /// <returns></returns> 1608 async public Task<T[]> SRandMembersAsync<T>(string key, int count = 1) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SRandMembersBytesAsync(k, count))); 1609 /// <summary> 1610 /// 移除集合中一个或多个成员 1611 /// </summary> 1612 /// <param name="key">不含prefix前辍</param> 1613 /// <param name="members">一个或多个成员</param> 1614 /// <returns></returns> 1615 async public Task<long> SRemAsync<T>(string key, params T[] members) 1616 { 1617 if (members == null || members.Any() == false) return 0; 1618 var args = members.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 1619 return await ExecuteScalarAsync(key, (c, k) => c.Value.SRemAsync(k, args)); 1620 } 1621 /// <summary> 1622 /// 返回所有给定集合的并集 1623 /// </summary> 1624 /// <param name="keys">不含prefix前辍</param> 1625 /// <returns></returns> 1626 public Task<string[]> SUnionAsync(params string[] keys) => NodesNotSupportAsync(keys, new string[0], (c, k) => c.Value.SUnionAsync(k)); 1627 /// <summary> 1628 /// 返回所有给定集合的并集 1629 /// </summary> 1630 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1631 /// <param name="keys">不含prefix前辍</param> 1632 /// <returns></returns> 1633 async public Task<T[]> SUnionAsync<T>(params string[] keys) => this.DeserializeRedisValueArrayInternal<T>(await NodesNotSupportAsync(keys, new byte[0][], (c, k) => c.Value.SUnionBytesAsync(k))); 1634 /// <summary> 1635 /// 所有给定集合的并集存储在 destination 集合中 1636 /// </summary> 1637 /// <param name="destination">新的无序集合,不含prefix前辍</param> 1638 /// <param name="keys">一个或多个无序集合,不含prefix前辍</param> 1639 /// <returns></returns> 1640 public Task<long> SUnionStoreAsync(string destination, params string[] keys) => NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.SUnionStoreAsync(k.First(), k.Skip(1).ToArray())); 1641 /// <summary> 1642 /// 迭代集合中的元素 1643 /// </summary> 1644 /// <param name="key">不含prefix前辍</param> 1645 /// <param name="cursor">位置</param> 1646 /// <param name="pattern">模式</param> 1647 /// <param name="count">数量</param> 1648 /// <returns></returns> 1649 public Task<RedisScan<string>> SScanAsync(string key, long cursor, string pattern = null, long? count = null) => ExecuteScalarAsync(key, (c, k) => c.Value.SScanAsync(k, cursor, pattern, count)); 1650 /// <summary> 1651 /// 迭代集合中的元素 1652 /// </summary> 1653 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1654 /// <param name="key">不含prefix前辍</param> 1655 /// <param name="cursor">位置</param> 1656 /// <param name="pattern">模式</param> 1657 /// <param name="count">数量</param> 1658 /// <returns></returns> 1659 async public Task<RedisScan<T>> SScanAsync<T>(string key, long cursor, string pattern = null, long? count = null) 1660 { 1661 var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.SScanBytesAsync(k, cursor, pattern, count)); 1662 return new RedisScan<T>(scan.Cursor, this.DeserializeRedisValueArrayInternal<T>(scan.Items)); 1663 } 1664 #endregion 1665 1666 #region List 1667 /// <summary> 1668 /// 通过索引获取列表中的元素 1669 /// </summary> 1670 /// <param name="key">不含prefix前辍</param> 1671 /// <param name="index">索引</param> 1672 /// <returns></returns> 1673 public Task<string> LIndexAsync(string key, long index) => ExecuteScalarAsync(key, (c, k) => c.Value.LIndexAsync(k, index)); 1674 /// <summary> 1675 /// 通过索引获取列表中的元素 1676 /// </summary> 1677 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1678 /// <param name="key">不含prefix前辍</param> 1679 /// <param name="index">索引</param> 1680 /// <returns></returns> 1681 async public Task<T> LIndexAsync<T>(string key, long index) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.LIndexBytesAsync(k, index))); 1682 /// <summary> 1683 /// 在列表中的元素前面插入元素 1684 /// </summary> 1685 /// <param name="key">不含prefix前辍</param> 1686 /// <param name="pivot">列表的元素</param> 1687 /// <param name="value">新元素</param> 1688 /// <returns></returns> 1689 public Task<long> LInsertBeforeAsync(string key, object pivot, object value) 1690 { 1691 var args = this.SerializeRedisValueInternal(value); 1692 return ExecuteScalarAsync(key, (c, k) => c.Value.LInsertAsync(k, RedisInsert.Before, pivot, args)); 1693 } 1694 /// <summary> 1695 /// 在列表中的元素后面插入元素 1696 /// </summary> 1697 /// <param name="key">不含prefix前辍</param> 1698 /// <param name="pivot">列表的元素</param> 1699 /// <param name="value">新元素</param> 1700 /// <returns></returns> 1701 public Task<long> LInsertAfterAsync(string key, object pivot, object value) 1702 { 1703 var args = this.SerializeRedisValueInternal(value); 1704 return ExecuteScalarAsync(key, (c, k) => c.Value.LInsertAsync(k, RedisInsert.After, pivot, args)); 1705 } 1706 /// <summary> 1707 /// 获取列表长度 1708 /// </summary> 1709 /// <param name="key">不含prefix前辍</param> 1710 /// <returns></returns> 1711 public Task<long> LLenAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.LLenAsync(k)); 1712 /// <summary> 1713 /// 移出并获取列表的第一个元素 1714 /// </summary> 1715 /// <param name="key">不含prefix前辍</param> 1716 /// <returns></returns> 1717 public Task<string> LPopAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.LPopAsync(k)); 1718 /// <summary> 1719 /// 移出并获取列表的第一个元素 1720 /// </summary> 1721 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1722 /// <param name="key">不含prefix前辍</param> 1723 /// <returns></returns> 1724 async public Task<T> LPopAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.LPopBytesAsync(k))); 1725 /// <summary> 1726 /// 将一个或多个值插入到列表头部 1727 /// </summary> 1728 /// <param name="key">不含prefix前辍</param> 1729 /// <param name="value">一个或多个值</param> 1730 /// <returns>执行 LPUSH 命令后,列表的长度</returns> 1731 async public Task<long> LPushAsync<T>(string key, params T[] value) 1732 { 1733 if (value == null || value.Any() == false) return 0; 1734 var args = value.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 1735 return await ExecuteScalarAsync(key, (c, k) => c.Value.LPushAsync(k, args)); 1736 } 1737 /// <summary> 1738 /// 将一个值插入到已存在的列表头部 1739 /// </summary> 1740 /// <param name="key">不含prefix前辍</param> 1741 /// <param name="value">值</param> 1742 /// <returns>执行 LPUSHX 命令后,列表的长度。</returns> 1743 public Task<long> LPushXAsync(string key, object value) 1744 { 1745 var args = this.SerializeRedisValueInternal(value); 1746 return ExecuteScalarAsync(key, (c, k) => c.Value.LPushXAsync(k, args)); 1747 } 1748 /// <summary> 1749 /// 获取列表指定范围内的元素 1750 /// </summary> 1751 /// <param name="key">不含prefix前辍</param> 1752 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1753 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1754 /// <returns></returns> 1755 public Task<string[]> LRangeAsync(string key, long start, long stop) => ExecuteScalarAsync(key, (c, k) => c.Value.LRangeAsync(k, start, stop)); 1756 /// <summary> 1757 /// 获取列表指定范围内的元素 1758 /// </summary> 1759 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1760 /// <param name="key">不含prefix前辍</param> 1761 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1762 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1763 /// <returns></returns> 1764 async public Task<T[]> LRangeAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.LRangeBytesAsync(k, start, stop))); 1765 /// <summary> 1766 /// 根据参数 count 的值,移除列表中与参数 value 相等的元素 1767 /// </summary> 1768 /// <param name="key">不含prefix前辍</param> 1769 /// <param name="count">移除的数量,大于0时从表头删除数量count,小于0时从表尾删除数量-count,等于0移除所有</param> 1770 /// <param name="value">元素</param> 1771 /// <returns></returns> 1772 public Task<long> LRemAsync(string key, long count, object value) 1773 { 1774 var args = this.SerializeRedisValueInternal(value); 1775 return ExecuteScalarAsync(key, (c, k) => c.Value.LRemAsync(k, count, args)); 1776 } 1777 /// <summary> 1778 /// 通过索引设置列表元素的值 1779 /// </summary> 1780 /// <param name="key">不含prefix前辍</param> 1781 /// <param name="index">索引</param> 1782 /// <param name="value">值</param> 1783 /// <returns></returns> 1784 async public Task<bool> LSetAsync(string key, long index, object value) 1785 { 1786 var args = this.SerializeRedisValueInternal(value); 1787 return await ExecuteScalar(key, (c, k) => c.Value.LSetAsync(k, index, args)) == "OK"; 1788 } 1789 /// <summary> 1790 /// 对一个列表进行修剪,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除 1791 /// </summary> 1792 /// <param name="key">不含prefix前辍</param> 1793 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 1794 /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param> 1795 /// <returns></returns> 1796 public Task<bool> LTrimAsync(string key, long start, long stop) => ExecuteScalarAsync(key, async (c, k) => await c.Value.LTrimAsync(k, start, stop) == "OK"); 1797 /// <summary> 1798 /// 移除并获取列表最后一个元素 1799 /// </summary> 1800 /// <param name="key">不含prefix前辍</param> 1801 /// <returns></returns> 1802 public Task<string> RPopAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.RPopAsync(k)); 1803 /// <summary> 1804 /// 移除并获取列表最后一个元素 1805 /// </summary> 1806 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1807 /// <param name="key">不含prefix前辍</param> 1808 /// <returns></returns> 1809 async public Task<T> RPopAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.RPopBytesAsync(k))); 1810 /// <summary> 1811 /// 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。 1812 /// 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。 1813 /// </summary> 1814 /// <param name="source">源key,不含prefix前辍</param> 1815 /// <param name="destination">目标key,不含prefix前辍</param> 1816 /// <returns></returns> 1817 public Task<string> RPopLPushAsync(string source, string destination) => NodesNotSupportAsync(new[] { source, destination }, null, (c, k) => c.Value.RPopLPushAsync(k.First(), k.Last())); 1818 /// <summary> 1819 /// 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。 1820 /// 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。 1821 /// </summary> 1822 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1823 /// <param name="source">源key,不含prefix前辍</param> 1824 /// <param name="destination">目标key,不含prefix前辍</param> 1825 /// <returns></returns> 1826 async public Task<T> RPopLPushAsync<T>(string source, string destination) => this.DeserializeRedisValueInternal<T>(await NodesNotSupportAsync(new[] { source, destination }, null, (c, k) => c.Value.RPopBytesLPushAsync(k.First(), k.Last()))); 1827 /// <summary> 1828 /// 在列表中添加一个或多个值 1829 /// </summary> 1830 /// <param name="key">不含prefix前辍</param> 1831 /// <param name="value">一个或多个值</param> 1832 /// <returns>执行 RPUSH 命令后,列表的长度</returns> 1833 async public Task<long> RPushAsync<T>(string key, params T[] value) 1834 { 1835 if (value == null || value.Any() == false) return 0; 1836 var args = value.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 1837 return await ExecuteScalarAsync(key, (c, k) => c.Value.RPushAsync(k, args)); 1838 } 1839 /// <summary> 1840 /// 为已存在的列表添加值 1841 /// </summary> 1842 /// <param name="key">不含prefix前辍</param> 1843 /// <param name="value">一个或多个值</param> 1844 /// <returns>执行 RPUSHX 命令后,列表的长度</returns> 1845 public Task<long> RPushXAsync(string key, object value) 1846 { 1847 var args = this.SerializeRedisValueInternal(value); 1848 return ExecuteScalar(key, (c, k) => c.Value.RPushXAsync(k, args)); 1849 } 1850 #endregion 1851 1852 #region Hash 1853 /// <summary> 1854 /// [redis-server 3.2.0] 返回hash指定field的value的字符串长度,如果hash或者field不存在,返回0. 1855 /// </summary> 1856 /// <param name="key">不含prefix前辍</param> 1857 /// <param name="field">字段</param> 1858 /// <returns></returns> 1859 public Task<long> HStrLenAsync(string key, string field) => ExecuteScalarAsync(key, (c, k) => c.Value.HStrLenAsync(k, field)); 1860 /// <summary> 1861 /// 删除一个或多个哈希表字段 1862 /// </summary> 1863 /// <param name="key">不含prefix前辍</param> 1864 /// <param name="fields">字段</param> 1865 /// <returns></returns> 1866 async public Task<long> HDelAsync(string key, params string[] fields) => fields == null || fields.Any() == false ? 0 : 1867 await ExecuteScalarAsync(key, (c, k) => c.Value.HDelAsync(k, fields)); 1868 /// <summary> 1869 /// 查看哈希表 key 中,指定的字段是否存在 1870 /// </summary> 1871 /// <param name="key">不含prefix前辍</param> 1872 /// <param name="field">字段</param> 1873 /// <returns></returns> 1874 public Task<bool> HExistsAsync(string key, string field) => ExecuteScalarAsync(key, (c, k) => c.Value.HExistsAsync(k, field)); 1875 /// <summary> 1876 /// 获取存储在哈希表中指定字段的值 1877 /// </summary> 1878 /// <param name="key">不含prefix前辍</param> 1879 /// <param name="field">字段</param> 1880 /// <returns></returns> 1881 public Task<string> HGetAsync(string key, string field) => ExecuteScalarAsync(key, (c, k) => c.Value.HGetAsync(k, field)); 1882 /// <summary> 1883 /// 获取存储在哈希表中指定字段的值 1884 /// </summary> 1885 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1886 /// <param name="key">不含prefix前辍</param> 1887 /// <param name="field">字段</param> 1888 /// <returns></returns> 1889 async public Task<T> HGetAsync<T>(string key, string field) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.HGetBytesAsync(k, field))); 1890 /// <summary> 1891 /// 获取在哈希表中指定 key 的所有字段和值 1892 /// </summary> 1893 /// <param name="key">不含prefix前辍</param> 1894 /// <returns></returns> 1895 public Task<Dictionary<string, string>> HGetAllAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.HGetAllAsync(k)); 1896 /// <summary> 1897 /// 获取在哈希表中指定 key 的所有字段和值 1898 /// </summary> 1899 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1900 /// <param name="key">不含prefix前辍</param> 1901 /// <returns></returns> 1902 async public Task<Dictionary<string, T>> HGetAllAsync<T>(string key) => this.DeserializeRedisValueDictionaryInternal<string, T>(await ExecuteScalarAsync(key, (c, k) => c.Value.HGetAllBytesAsync(k))); 1903 /// <summary> 1904 /// 为哈希表 key 中的指定字段的整数值加上增量 increment 1905 /// </summary> 1906 /// <param name="key">不含prefix前辍</param> 1907 /// <param name="field">字段</param> 1908 /// <param name="value">增量值(默认=1)</param> 1909 /// <returns></returns> 1910 public Task<long> HIncrByAsync(string key, string field, long value = 1) => ExecuteScalarAsync(key, (c, k) => c.Value.HIncrByAsync(k, field, value)); 1911 /// <summary> 1912 /// 为哈希表 key 中的指定字段的整数值加上增量 increment 1913 /// </summary> 1914 /// <param name="key">不含prefix前辍</param> 1915 /// <param name="field">字段</param> 1916 /// <param name="value">增量值(默认=1)</param> 1917 /// <returns></returns> 1918 public Task<decimal> HIncrByFloatAsync(string key, string field, decimal value) => ExecuteScalarAsync(key, (c, k) => c.Value.HIncrByFloatAsync(k, field, value)); 1919 /// <summary> 1920 /// 获取所有哈希表中的字段 1921 /// </summary> 1922 /// <param name="key">不含prefix前辍</param> 1923 /// <returns></returns> 1924 public Task<string[]> HKeysAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.HKeysAsync(k)); 1925 /// <summary> 1926 /// 获取哈希表中字段的数量 1927 /// </summary> 1928 /// <param name="key">不含prefix前辍</param> 1929 /// <returns></returns> 1930 public Task<long> HLenAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.HLenAsync(k)); 1931 /// <summary> 1932 /// 获取存储在哈希表中多个字段的值 1933 /// </summary> 1934 /// <param name="key">不含prefix前辍</param> 1935 /// <param name="fields">字段</param> 1936 /// <returns></returns> 1937 async public Task<string[]> HMGetAsync(string key, params string[] fields) => fields == null || fields.Any() == false ? new string[0] : 1938 await ExecuteScalarAsync(key, (c, k) => c.Value.HMGetAsync(k, fields)); 1939 /// <summary> 1940 /// 获取存储在哈希表中多个字段的值 1941 /// </summary> 1942 /// <typeparam name="T">byte[] 或其他类型</typeparam> 1943 /// <param name="key">不含prefix前辍</param> 1944 /// <param name="fields">一个或多个字段</param> 1945 /// <returns></returns> 1946 async public Task<T[]> HMGetAsync<T>(string key, params string[] fields) => fields == null || fields.Any() == false ? new T[0] : 1947 this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.HMGetBytesAsync(k, fields))); 1948 /// <summary> 1949 /// 同时将多个 field-value (域-值)对设置到哈希表 key 中 1950 /// </summary> 1951 /// <param name="key">不含prefix前辍</param> 1952 /// <param name="keyValues">key1 value1 [key2 value2]</param> 1953 /// <returns></returns> 1954 async public Task<bool> HMSetAsync(string key, params object[] keyValues) 1955 { 1956 if (keyValues == null || keyValues.Any() == false) return false; 1957 if (keyValues.Length % 2 != 0) throw new Exception("keyValues 参数是键值对,不应该出现奇数(数量),请检查使用姿势。"); 1958 var parms = new List<object>(); 1959 for (var a = 0; a < keyValues.Length; a += 2) 1960 { 1961 var k = string.Concat(keyValues[a]); 1962 var v = keyValues[a + 1]; 1963 if (string.IsNullOrEmpty(k)) throw new Exception("keyValues 参数是键值对,并且 key 不可为空"); 1964 parms.Add(k); 1965 parms.Add(this.SerializeRedisValueInternal(v)); 1966 } 1967 return await ExecuteScalarAsync(key, (c, k) => c.Value.HMSetAsync(k, parms.ToArray())) == "OK"; 1968 } 1969 1970 async public Task<bool> HMSetAsync(string key, Dictionary<string,string> keyValues) 1971 { 1972 if (keyValues == null || keyValues.Any() == false) return false; 1973 var parms = new List<object>(); 1974 foreach(var item in keyValues) 1975 { 1976 parms.Add(item.Key); 1977 parms.Add(this.SerializeRedisValueInternal(item.Value)); 1978 } 1979 return await ExecuteScalarAsync(key, (c, k) => c.Value.HMSetAsync(k, parms.ToArray())) == "OK"; 1980 } 1981 /// <summary> 1982 /// 将哈希表 key 中的字段 field 的值设为 value 1983 /// </summary> 1984 /// <param name="key">不含prefix前辍</param> 1985 /// <param name="field">字段</param> 1986 /// <param name="value">值</param> 1987 /// <returns>如果字段是哈希表中的一个新建字段,并且值设置成功,返回true。如果哈希表中域字段已经存在且旧值已被新值覆盖,返回false。</returns> 1988 public Task<bool> HSetAsync(string key, string field, object value) 1989 { 1990 var args = this.SerializeRedisValueInternal(value); 1991 return ExecuteScalarAsync(key, (c, k) => c.Value.HSetAsync(k, field, args)); 1992 } 1993 /// <summary> 1994 /// 只有在字段 field 不存在时,设置哈希表字段的值 1995 /// </summary> 1996 /// <param name="key">不含prefix前辍</param> 1997 /// <param name="field">字段</param> 1998 /// <param name="value">值(string 或 byte[])</param> 1999 /// <returns></returns> 2000 public Task<bool> HSetNxAsync(string key, string field, object value) 2001 { 2002 var args = this.SerializeRedisValueInternal(value); 2003 return ExecuteScalarAsync(key, (c, k) => c.Value.HSetNxAsync(k, field, args)); 2004 } 2005 /// <summary> 2006 /// 获取哈希表中所有值 2007 /// </summary> 2008 /// <param name="key">不含prefix前辍</param> 2009 /// <returns></returns> 2010 public Task<string[]> HValsAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.HValsAsync(k)); 2011 /// <summary> 2012 /// 获取哈希表中所有值 2013 /// </summary> 2014 /// <typeparam name="T">byte[] 或其他类型</typeparam> 2015 /// <param name="key">不含prefix前辍</param> 2016 /// <returns></returns> 2017 async public Task<T[]> HValsAsync<T>(string key) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.HValsBytesAsync(k))); 2018 /// <summary> 2019 /// 迭代哈希表中的键值对 2020 /// </summary> 2021 /// <param name="key">不含prefix前辍</param> 2022 /// <param name="cursor">位置</param> 2023 /// <param name="pattern">模式</param> 2024 /// <param name="count">数量</param> 2025 /// <returns></returns> 2026 async public Task<RedisScan<(string field, string value)>> HScanAsync(string key, long cursor, string pattern = null, long? count = null) 2027 { 2028 var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.HScanAsync(k, cursor, pattern, count)); 2029 return new RedisScan<(string, string)>(scan.Cursor, scan.Items.Select(z => (z.Item1, z.Item2)).ToArray()); 2030 } 2031 /// <summary> 2032 /// 迭代哈希表中的键值对 2033 /// </summary> 2034 /// <typeparam name="T">byte[] 或其他类型</typeparam> 2035 /// <param name="key">不含prefix前辍</param> 2036 /// <param name="cursor">位置</param> 2037 /// <param name="pattern">模式</param> 2038 /// <param name="count">数量</param> 2039 /// <returns></returns> 2040 async public Task<RedisScan<(string field, T value)>> HScanAsync<T>(string key, long cursor, string pattern = null, long? count = null) 2041 { 2042 var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.HScanBytesAsync(k, cursor, pattern, count)); 2043 return new RedisScan<(string, T)>(scan.Cursor, scan.Items.Select(z => (z.Item1, this.DeserializeRedisValueInternal<T>(z.Item2))).ToArray()); 2044 } 2045 #endregion 2046 2047 #region String 2048 /// <summary> 2049 /// 如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾 2050 /// </summary> 2051 /// <param name="key">不含prefix前辍</param> 2052 /// <param name="value">字符串</param> 2053 /// <returns>追加指定值之后, key 中字符串的长度</returns> 2054 public Task<long> AppendAsync(string key, object value) 2055 { 2056 var args = this.SerializeRedisValueInternal(value); 2057 return ExecuteScalarAsync(key, (c, k) => c.Value.AppendAsync(k, args)); 2058 } 2059 /// <summary> 2060 /// 计算给定位置被设置为 1 的比特位的数量 2061 /// </summary> 2062 /// <param name="key">不含prefix前辍</param> 2063 /// <param name="start">开始位置</param> 2064 /// <param name="end">结束位置</param> 2065 /// <returns></returns> 2066 public Task<long> BitCountAsync(string key, long start, long end) => ExecuteScalarAsync(key, (c, k) => c.Value.BitCountAsync(k, start, end)); 2067 /// <summary> 2068 /// 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上 2069 /// </summary> 2070 /// <param name="op">And | Or | XOr | Not</param> 2071 /// <param name="destKey">不含prefix前辍</param> 2072 /// <param name="keys">不含prefix前辍</param> 2073 /// <returns>保存到 destkey 的长度,和输入 key 中最长的长度相等</returns> 2074 async public Task<long> BitOpAsync(RedisBitOp op, string destKey, params string[] keys) 2075 { 2076 if (string.IsNullOrEmpty(destKey)) throw new Exception("destKey 不能为空"); 2077 if (keys == null || keys.Length == 0) throw new Exception("keys 不能为空"); 2078 return await NodesNotSupportAsync(new[] { destKey }.Concat(keys).ToArray(), 0, (c, k) => c.Value.BitOpAsync(op, k.First(), k.Skip(1).ToArray())); 2079 } 2080 /// <summary> 2081 /// 对 key 所储存的值,查找范围内第一个被设置为1或者0的bit位 2082 /// </summary> 2083 /// <param name="key">不含prefix前辍</param> 2084 /// <param name="bit">查找值</param> 2085 /// <param name="start">开始位置,-1是最后一个,-2是倒数第二个</param> 2086 /// <param name="end">结果位置,-1是最后一个,-2是倒数第二个</param> 2087 /// <returns>返回范围内第一个被设置为1或者0的bit位</returns> 2088 public Task<long> BitPosAsync(string key, bool bit, long? start = null, long? end = null) => ExecuteScalarAsync(key, (c, k) => c.Value.BitPosAsync(k, bit, start, end)); 2089 /// <summary> 2090 /// 获取指定 key 的值 2091 /// </summary> 2092 /// <param name="key">不含prefix前辍</param> 2093 /// <returns></returns> 2094 public Task<string> GetAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.GetAsync(k)); 2095 /// <summary> 2096 /// 获取指定 key 的值 2097 /// </summary> 2098 /// <typeparam name="T">byte[] 或其他类型</typeparam> 2099 /// <param name="key">不含prefix前辍</param> 2100 /// <returns></returns> 2101 async public Task<T> GetAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.GetBytesAsync(k))); 2102 /// <summary> 2103 /// 对 key 所储存的值,获取指定偏移量上的位(bit) 2104 /// </summary> 2105 /// <param name="key">不含prefix前辍</param> 2106 /// <param name="offset">偏移量</param> 2107 /// <returns></returns> 2108 public Task<bool> GetBitAsync(string key, uint offset) => ExecuteScalarAsync(key, (c, k) => c.Value.GetBitAsync(k, offset)); 2109 /// <summary> 2110 /// 返回 key 中字符串值的子字符 2111 /// </summary> 2112 /// <param name="key">不含prefix前辍</param> 2113 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 2114 /// <param name="end">结束位置,0表示第一个元素,-1表示最后一个元素</param> 2115 /// <returns></returns> 2116 public Task<string> GetRangeAsync(string key, long start, long end) => ExecuteScalarAsync(key, (c, k) => c.Value.GetRangeAsync(k, start, end)); 2117 /// <summary> 2118 /// 返回 key 中字符串值的子字符 2119 /// </summary> 2120 /// <typeparam name="T">byte[] 或其他类型</typeparam> 2121 /// <param name="key">不含prefix前辍</param> 2122 /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param> 2123 /// <param name="end">结束位置,0表示第一个元素,-1表示最后一个元素</param> 2124 /// <returns></returns> 2125 async public Task<T> GetRangeAsync<T>(string key, long start, long end) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.GetRangeBytesAsync(k, start, end))); 2126 /// <summary> 2127 /// 将给定 key 的值设为 value ,并返回 key 的旧值(old value) 2128 /// </summary> 2129 /// <param name="key">不含prefix前辍</param> 2130 /// <param name="value">值</param> 2131 /// <returns></returns> 2132 public Task<string> GetSetAsync(string key, object value) 2133 { 2134 var args = this.SerializeRedisValueInternal(value); 2135 return ExecuteScalarAsync(key, (c, k) => c.Value.GetSetAsync(k, args)); 2136 } 2137 /// <summary> 2138 /// 将给定 key 的值设为 value ,并返回 key 的旧值(old value) 2139 /// </summary> 2140 /// <typeparam name="T">byte[] 或其他类型</typeparam> 2141 /// <param name="key">不含prefix前辍</param> 2142 /// <param name="value">值</param> 2143 /// <returns></returns> 2144 async public Task<T> GetSetAsync<T>(string key, object value) 2145 { 2146 var args = this.SerializeRedisValueInternal(value); 2147 return this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.GetSetBytesAsync(k, args))); 2148 } 2149 /// <summary> 2150 /// 将 key 所储存的值加上给定的增量值(increment) 2151 /// </summary> 2152 /// <param name="key">不含prefix前辍</param> 2153 /// <param name="value">增量值(默认=1)</param> 2154 /// <returns></returns> 2155 public Task<long> IncrByAsync(string key, long value = 1) => ExecuteScalarAsync(key, (c, k) => c.Value.IncrByAsync(k, value)); 2156 /// <summary> 2157 /// 将 key 所储存的值加上给定的浮点增量值(increment) 2158 /// </summary> 2159 /// <param name="key">不含prefix前辍</param> 2160 /// <param name="value">增量值(默认=1)</param> 2161 /// <returns></returns> 2162 public Task<decimal> IncrByFloatAsync(string key, decimal value) => ExecuteScalarAsync(key, (c, k) => c.Value.IncrByFloatAsync(k, value)); 2163 /// <summary> 2164 /// 将 key 中储存的数字值减一。 2165 /// </summary> 2166 /// <param name="key">不含prefix前辍</param> 2167 /// <returns></returns> 2168 public long Decr(string key) => ExecuteScalar(key, (c, k) => c.Value.Decr(key)); 2169 /// <summary> 2170 /// 将 key 中储存的数字值减一。 2171 /// </summary> 2172 /// <param name="key">不含prefix前辍</param> 2173 /// <returns></returns> 2174 public Task<long> DecrAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.DecrAsync(key)); 2175 /// <summary> 2176 /// key 所储存的值减去给定的减量值(decrement) 。 2177 /// </summary> 2178 /// <param name="key">不含prefix前辍</param> 2179 /// <param name="value">增量值(默认=1)</param> 2180 /// <returns></returns> 2181 public long DecrBy(string key, long value = 1) => ExecuteScalar(key, (c, k) => c.Value.DecrBy(k, value)); 2182 /// <summary> 2183 /// key 所储存的值减去给定的减量值(decrement) 。 2184 /// </summary> 2185 /// <param name="key">不含prefix前辍</param> 2186 /// <param name="value">增量值(默认=1)</param> 2187 /// <returns></returns> 2188 public Task<long> DecrByAsync(string key, long value = 1) => ExecuteScalarAsync(key, (c, k) => c.Value.DecrByAsync(k, value)); 2189 /// <summary> 2190 /// 获取多个指定 key 的值(数组) 2191 /// </summary> 2192 /// <param name="keys">不含prefix前辍</param> 2193 /// <returns></returns> 2194 public Task<string[]> MGetAsync(params string[] keys) => ExecuteArrayAsync(keys, (c, k) => c.Value.MGetAsync(k)); 2195 /// <summary> 2196 /// 获取多个指定 key 的值(数组) 2197 /// </summary> 2198 /// <typeparam name="T">byte[] 或其他类型</typeparam> 2199 /// <param name="keys">不含prefix前辍</param> 2200 /// <returns></returns> 2201 async public Task<T[]> MGetAsync<T>(params string[] keys) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteArrayAsync(keys, (c, k) => c.Value.MGetBytesAsync(k))); 2202 /// <summary> 2203 /// 同时设置一个或多个 key-value 对 2204 /// </summary> 2205 /// <param name="keyValues">key1 value1 [key2 value2]</param> 2206 /// <returns></returns> 2207 public Task<bool> MSetAsync(params object[] keyValues) => MSetInternalAsync(RedisExistence.Xx, keyValues); 2208 /// <summary> 2209 /// 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在 2210 /// </summary> 2211 /// <param name="keyValues">key1 value1 [key2 value2]</param> 2212 /// <returns></returns> 2213 public Task<bool> MSetNxAsync(params object[] keyValues) => MSetInternalAsync(RedisExistence.Nx, keyValues); 2214 async internal Task<bool> MSetInternalAsync(RedisExistence exists, params object[] keyValues) 2215 { 2216 if (keyValues == null || keyValues.Any() == false) return false; 2217 if (keyValues.Length % 2 != 0) throw new Exception("keyValues 参数是键值对,不应该出现奇数(数量),请检查使用姿势。"); 2218 var dic = new Dictionary<string, object>(); 2219 for (var a = 0; a < keyValues.Length; a += 2) 2220 { 2221 var k = string.Concat(keyValues[a]); 2222 var v = this.SerializeRedisValueInternal(keyValues[a + 1]); 2223 if (string.IsNullOrEmpty(k)) throw new Exception("keyValues 参数是键值对,并且 key 不可为空"); 2224 if (dic.ContainsKey(k)) dic[k] = v; 2225 else dic.Add(k, v); 2226 } 2227 Func<Object<RedisClient>, string[], Task<long>> handle = async (c, k) => 2228 { 2229 var prefix = (c.Pool as RedisClientPool)?.Prefix; 2230 var parms = new object[k.Length * 2]; 2231 for (var a = 0; a < k.Length; a++) 2232 { 2233 parms[a * 2] = k[a]; 2234 parms[a * 2 + 1] = dic[string.IsNullOrEmpty(prefix) ? k[a] : k[a].Substring(prefix.Length)]; 2235 } 2236 if (exists == RedisExistence.Nx) return await c.Value.MSetNxAsync(parms) ? 1 : 0; 2237 return await c.Value.MSetAsync(parms) == "OK" ? 1 : 0; 2238 }; 2239 if (exists == RedisExistence.Nx) return await NodesNotSupportAsync(dic.Keys.ToArray(), 0, handle) > 0; 2240 return await ExecuteNonQueryAsync(dic.Keys.ToArray(), handle) > 0; 2241 } 2242 /// <summary> 2243 /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 2244 /// </summary> 2245 /// <param name="key">不含prefix前辍</param> 2246 /// <param name="value">值</param> 2247 /// <param name="expireSeconds">过期(秒单位)</param> 2248 /// <param name="exists">Nx, Xx</param> 2249 /// <returns></returns> 2250 async public Task<bool> SetAsync(string key, object value, int expireSeconds = -1, RedisExistence? exists = null) 2251 { 2252 object redisValule = this.SerializeRedisValueInternal(value); 2253 if (expireSeconds <= 0 && exists == null) return await ExecuteScalarAsync(key, (c, k) => c.Value.SetAsync(k, redisValule)) == "OK"; 2254 if (expireSeconds <= 0 && exists != null) return await ExecuteScalarAsync(key, (c, k) => c.Value.SetAsync(k, redisValule, null, exists)) == "OK"; 2255 if (expireSeconds > 0 && exists == null) return await ExecuteScalarAsync(key, (c, k) => c.Value.SetAsync(k, redisValule, expireSeconds, null)) == "OK"; 2256 if (expireSeconds > 0 && exists != null) return await ExecuteScalarAsync(key, (c, k) => c.Value.SetAsync(k, redisValule, expireSeconds, exists)) == "OK"; 2257 return false; 2258 } 2259 async public Task<bool> SetAsync(string key, object value, TimeSpan expire, RedisExistence? exists = null) 2260 { 2261 object redisValule = this.SerializeRedisValueInternal(value); 2262 if (expire <= TimeSpan.Zero && exists == null) return await ExecuteScalar(key, (c, k) => c.Value.SetAsync(k, redisValule)) == "OK"; 2263 if (expire <= TimeSpan.Zero && exists != null) return await ExecuteScalar(key, (c, k) => c.Value.SetAsync(k, redisValule, null, exists)) == "OK"; 2264 if (expire > TimeSpan.Zero && exists == null) return await ExecuteScalar(key, (c, k) => c.Value.SetAsync(k, redisValule, expire, null)) == "OK"; 2265 if (expire > TimeSpan.Zero && exists != null) return await ExecuteScalar(key, (c, k) => c.Value.SetAsync(k, redisValule, expire, exists)) == "OK"; 2266 return false; 2267 } 2268 /// <summary> 2269 /// 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit) 2270 /// </summary> 2271 /// <param name="key">不含prefix前辍</param> 2272 /// <param name="offset">偏移量</param> 2273 /// <param name="value">值</param> 2274 /// <returns></returns> 2275 public Task<bool> SetBitAsync(string key, uint offset, bool value) => ExecuteScalarAsync(key, (c, k) => c.Value.SetBitAsync(k, offset, value)); 2276 /// <summary> 2277 /// 只有在 key 不存在时设置 key 的值 2278 /// </summary> 2279 /// <param name="key">不含prefix前辍</param> 2280 /// <param name="value">值</param> 2281 /// <returns></returns> 2282 public Task<bool> SetNxAsync(string key, object value) 2283 { 2284 var args = this.SerializeRedisValueInternal(value); 2285 return ExecuteScalarAsync(key, (c, k) => c.Value.SetNxAsync(k, args)); 2286 } 2287 /// <summary> 2288 /// 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始 2289 /// </summary> 2290 /// <param name="key">不含prefix前辍</param> 2291 /// <param name="offset">偏移量</param> 2292 /// <param name="value">值</param> 2293 /// <returns>被修改后的字符串长度</returns> 2294 public Task<long> SetRangeAsync(string key, uint offset, object value) 2295 { 2296 var args = this.SerializeRedisValueInternal(value); 2297 return ExecuteScalarAsync(key, (c, k) => c.Value.SetRangeAsync(k, offset, args)); 2298 } 2299 /// <summary> 2300 /// 返回 key 所储存的字符串值的长度 2301 /// </summary> 2302 /// <param name="key">不含prefix前辍</param> 2303 /// <returns></returns> 2304 public Task<long> StrLenAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.StrLenAsync(k)); 2305 #endregion 2306 2307 #region Key 2308 /// <summary> 2309 /// [redis-server 3.2.1] 修改指定key(s) 最后访问时间 若key不存在,不做操作 2310 /// </summary> 2311 /// <param name="key">不含prefix前辍</param> 2312 /// <returns></returns> 2313 public Task<long> TouchAsync(params string[] key) => ExecuteNonQueryAsync(key, (c, k) => c.Value.TouchAsync(k)); 2314 /// <summary> 2315 /// [redis-server 4.0.0] Delete a key, 该命令和DEL十分相似:删除指定的key(s),若key不存在则该key被跳过。但是,相比DEL会产生阻塞,该命令会在另一个线程中回收内存,因此它是非阻塞的。 这也是该命令名字的由来:仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。 2316 /// </summary> 2317 /// <param name="key">不含prefix前辍</param> 2318 /// <returns></returns> 2319 public Task<long> UnLinkAsync(params string[] key) => ExecuteNonQueryAsync(key, (c, k) => c.Value.UnLinkAsync(k)); 2320 /// <summary> 2321 /// 用于在 key 存在时删除 key 2322 /// </summary> 2323 /// <param name="key">不含prefix前辍</param> 2324 /// <returns></returns> 2325 public Task<long> DelAsync(params string[] key) => ExecuteNonQueryAsync(key, (c, k) => c.Value.DelAsync(k)); 2326 /// <summary> 2327 /// 序列化给定 key ,并返回被序列化的值 2328 /// </summary> 2329 /// <param name="key">不含prefix前辍</param> 2330 /// <returns></returns> 2331 public Task<byte[]> DumpAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.DumpAsync(k)); 2332 /// <summary> 2333 /// 检查给定 key 是否存在 2334 /// </summary> 2335 /// <param name="key">不含prefix前辍</param> 2336 /// <returns></returns> 2337 public Task<bool> ExistsAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ExistsAsync(k)); 2338 /// <summary> 2339 /// [redis-server 3.0] 检查给定多个 key 是否存在 2340 /// </summary> 2341 /// <param name="keys">不含prefix前辍</param> 2342 /// <returns></returns> 2343 public Task<long> ExistsAsync(string[] keys) => NodesNotSupportAsync(keys, 0, (c, k) => c.Value.ExistsAsync(k)); 2344 /// <summary> 2345 /// 为给定 key 设置过期时间 2346 /// </summary> 2347 /// <param name="key">不含prefix前辍</param> 2348 /// <param name="seconds">过期秒数</param> 2349 /// <returns></returns> 2350 public Task<bool> ExpireAsync(string key, int seconds) => ExecuteScalarAsync(key, (c, k) => c.Value.ExpireAsync(k, seconds)); 2351 /// <summary> 2352 /// 为给定 key 设置过期时间 2353 /// </summary> 2354 /// <param name="key">不含prefix前辍</param> 2355 /// <param name="expire">过期时间</param> 2356 /// <returns></returns> 2357 public Task<bool> ExpireAsync(string key, TimeSpan expire) => ExecuteScalarAsync(key, (c, k) => c.Value.ExpireAsync(k, expire)); 2358 /// <summary> 2359 /// 为给定 key 设置过期时间 2360 /// </summary> 2361 /// <param name="key">不含prefix前辍</param> 2362 /// <param name="expire">过期时间</param> 2363 /// <returns></returns> 2364 public Task<bool> ExpireAtAsync(string key, DateTime expire) => ExecuteScalarAsync(key, (c, k) => c.Value.ExpireAtAsync(k, expire)); 2365 /// <summary> 2366 /// 查找所有分区节点中符合给定模式(pattern)的 key 2367 /// </summary> 2368 /// <param name="pattern">如:runoob*</param> 2369 /// <returns></returns> 2370 async public Task<string[]> KeysAsync(string pattern) 2371 { 2372 List<string> ret = new List<string>(); 2373 foreach (var pool in Nodes) 2374 ret.AddRange(await GetAndExecuteAsync(pool.Value, conn => conn.Value.KeysAsync(pattern))); 2375 return ret.ToArray(); 2376 } 2377 /// <summary> 2378 /// 将当前数据库的 key 移动到给定的数据库 db 当中 2379 /// </summary> 2380 /// <param name="key">不含prefix前辍</param> 2381 /// <param name="database">数据库</param> 2382 /// <returns></returns> 2383 public Task<bool> MoveAsync(string key, int database) => ExecuteScalarAsync(key, (c, k) => c.Value.MoveAsync(k, database)); 2384 /// <summary> 2385 /// 该返回给定 key 锁储存的值所使用的内部表示(representation) 2386 /// </summary> 2387 /// <param name="key">不含prefix前辍</param> 2388 /// <returns></returns> 2389 public Task<string> ObjectEncodingAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ObjectEncodingAsync(k)); 2390 /// <summary> 2391 /// 该返回给定 key 引用所储存的值的次数。此命令主要用于除错 2392 /// </summary> 2393 /// <param name="key">不含prefix前辍</param> 2394 /// <returns></returns> 2395 public Task<long?> ObjectRefCountAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ObjectAsync(RedisObjectSubCommand.RefCount, k)); 2396 /// <summary> 2397 /// 返回给定 key 自储存以来的空转时间(idle, 没有被读取也没有被写入),以秒为单位 2398 /// </summary> 2399 /// <param name="key">不含prefix前辍</param> 2400 /// <returns></returns> 2401 public Task<long?> ObjectIdleTimeAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ObjectAsync(RedisObjectSubCommand.IdleTime, k)); 2402 /// <summary> 2403 /// 移除 key 的过期时间,key 将持久保持 2404 /// </summary> 2405 /// <param name="key">不含prefix前辍</param> 2406 /// <returns></returns> 2407 public Task<bool> PersistAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.PersistAsync(k)); 2408 /// <summary> 2409 /// 为给定 key 设置过期时间(毫秒) 2410 /// </summary> 2411 /// <param name="key">不含prefix前辍</param> 2412 /// <param name="milliseconds">过期毫秒数</param> 2413 /// <returns></returns> 2414 public Task<bool> PExpireAsync(string key, int milliseconds) => ExecuteScalarAsync(key, (c, k) => c.Value.PExpireAsync(k, milliseconds)); 2415 /// <summary> 2416 /// 为给定 key 设置过期时间(毫秒) 2417 /// </summary> 2418 /// <param name="key">不含prefix前辍</param> 2419 /// <param name="expire">过期时间</param> 2420 /// <returns></returns> 2421 public Task<bool> PExpireAsync(string key, TimeSpan expire) => ExecuteScalarAsync(key, (c, k) => c.Value.PExpireAsync(k, expire)); 2422 /// <summary> 2423 /// 为给定 key 设置过期时间(毫秒) 2424 /// </summary> 2425 /// <param name="key">不含prefix前辍</param> 2426 /// <param name="expire">过期时间</param> 2427 /// <returns></returns> 2428 public Task<bool> PExpireAtAsync(string key, DateTime expire) => ExecuteScalarAsync(key, (c, k) => c.Value.PExpireAtAsync(k, expire)); 2429 /// <summary> 2430 /// 以毫秒为单位返回 key 的剩余的过期时间 2431 /// </summary> 2432 /// <param name="key">不含prefix前辍</param> 2433 /// <returns></returns> 2434 public Task<long> PTtlAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.PTtlAsync(k)); 2435 /// <summary> 2436 /// 从所有节点中随机返回一个 key 2437 /// </summary> 2438 /// <returns>返回的 key 如果包含 prefix前辍,则会去除后返回</returns> 2439 public Task<string> RandomKeyAsync() => GetAndExecuteAsync(Nodes[NodesIndex[_rnd.Next(0, NodesIndex.Count)]], async c => 2440 { 2441 var rk = await c.Value.RandomKeyAsync(); 2442 var prefix = (c.Pool as RedisClientPool).Prefix; 2443 if (string.IsNullOrEmpty(prefix) == false && rk.StartsWith(prefix)) return rk.Substring(prefix.Length); 2444 return rk; 2445 }); 2446 /// <summary> 2447 /// 修改 key 的名称 2448 /// </summary> 2449 /// <param name="key">旧名称,不含prefix前辍</param> 2450 /// <param name="newKey">新名称,不含prefix前辍</param> 2451 /// <returns></returns> 2452 async public Task<bool> RenameAsync(string key, string newKey) 2453 { 2454 string rule = string.Empty; 2455 if (Nodes.Count > 1) 2456 { 2457 var rule1 = NodeRuleRaw(key); 2458 var rule2 = NodeRuleRaw(newKey); 2459 if (rule1 != rule2) 2460 { 2461 var ret = StartPipe(a => a.Dump(key).Del(key)); 2462 int.TryParse(ret[1]?.ToString(), out var tryint); 2463 if (ret[0] == null || tryint <= 0) return false; 2464 return await RestoreAsync(newKey, (byte[])ret[0]); 2465 } 2466 rule = rule1; 2467 } 2468 var pool = Nodes.TryGetValue(rule, out var b) ? b : Nodes.First().Value; 2469 var key1 = string.Concat(pool.Prefix, key); 2470 var key2 = string.Concat(pool.Prefix, newKey); 2471 return await GetAndExecuteAsync(pool, conn => conn.Value.RenameAsync(key1, key2)) == "OK"; 2472 } 2473 /// <summary> 2474 /// 修改 key 的名称 2475 /// </summary> 2476 /// <param name="key">旧名称,不含prefix前辍</param> 2477 /// <param name="newKey">新名称,不含prefix前辍</param> 2478 /// <returns></returns> 2479 public Task<bool> RenameNxAsync(string key, string newKey) => NodesNotSupportAsync(new[] { key, newKey }, false, (c, k) => c.Value.RenameNxAsync(k.First(), k.Last())); 2480 /// <summary> 2481 /// 反序列化给定的序列化值,并将它和给定的 key 关联 2482 /// </summary> 2483 /// <param name="key">不含prefix前辍</param> 2484 /// <param name="serializedValue">序列化值</param> 2485 /// <returns></returns> 2486 public Task<bool> RestoreAsync(string key, byte[] serializedValue) => ExecuteScalarAsync(key, async (c, k) => await c.Value.RestoreAsync(k, 0, serializedValue) == "OK"); 2487 /// <summary> 2488 /// 反序列化给定的序列化值,并将它和给定的 key 关联 2489 /// </summary> 2490 /// <param name="key">不含prefix前辍</param> 2491 /// <param name="ttlMilliseconds">毫秒为单位为 key 设置生存时间</param> 2492 /// <param name="serializedValue">序列化值</param> 2493 /// <returns></returns> 2494 public Task<bool> RestoreAsync(string key, long ttlMilliseconds, byte[] serializedValue) => ExecuteScalarAsync(key, async (c, k) => await c.Value.RestoreAsync(k, ttlMilliseconds, serializedValue) == "OK"); 2495 /// <summary> 2496 /// 返回给定列表、集合、有序集合 key 中经过排序的元素,参数资料:http://doc.redisfans.com/key/sort.html 2497 /// </summary> 2498 /// <param name="key">列表、集合、有序集合,不含prefix前辍</param> 2499 /// <param name="offset">偏移量</param> 2500 /// <param name="count">数量</param> 2501 /// <param name="by">排序字段</param> 2502 /// <param name="dir">排序方式</param> 2503 /// <param name="isAlpha">对字符串或数字进行排序</param> 2504 /// <param name="get">根据排序的结果来取出相应的键值</param> 2505 /// <returns></returns> 2506 public Task<string[]> SortAsync(string key, long? count = null, long offset = 0, string by = null, RedisSortDir? dir = null, bool? isAlpha = null, params string[] get) => 2507 NodesNotSupportAsync(key, (c, k) => c.Value.SortAsync(k, offset, count, by, dir, isAlpha, get)); 2508 /// <summary> 2509 /// 保存给定列表、集合、有序集合 key 中经过排序的元素,参数资料:http://doc.redisfans.com/key/sort.html 2510 /// </summary> 2511 /// <param name="key">列表、集合、有序集合,不含prefix前辍</param> 2512 /// <param name="destination">目标key,不含prefix前辍</param> 2513 /// <param name="offset">偏移量</param> 2514 /// <param name="count">数量</param> 2515 /// <param name="by">排序字段</param> 2516 /// <param name="dir">排序方式</param> 2517 /// <param name="isAlpha">对字符串或数字进行排序</param> 2518 /// <param name="get">根据排序的结果来取出相应的键值</param> 2519 /// <returns></returns> 2520 public Task<long> SortAndStoreAsync(string key, string destination, long? count = null, long offset = 0, string by = null, RedisSortDir? dir = null, bool? isAlpha = null, params string[] get) => 2521 NodesNotSupportAsync(key, (c, k) => c.Value.SortAndStoreAsync(k, (c.Pool as RedisClientPool)?.Prefix + destination, offset, count, by, dir, isAlpha, get)); 2522 /// <summary> 2523 /// 以秒为单位,返回给定 key 的剩余生存时间 2524 /// </summary> 2525 /// <param name="key">不含prefix前辍</param> 2526 /// <returns></returns> 2527 public Task<long> TtlAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.TtlAsync(k)); 2528 /// <summary> 2529 /// 返回 key 所储存的值的类型 2530 /// </summary> 2531 /// <param name="key">不含prefix前辍</param> 2532 /// <returns></returns> 2533 async public Task<KeyType> TypeAsync(string key) => Enum.TryParse(await ExecuteScalarAsync(key, (c, k) => c.Value.TypeAsync(k)), true, out KeyType tryenum) ? tryenum : KeyType.None; 2534 /// <summary> 2535 /// 迭代当前数据库中的数据库键 2536 /// </summary> 2537 /// <param name="cursor">位置</param> 2538 /// <param name="pattern">模式</param> 2539 /// <param name="count">数量</param> 2540 /// <returns></returns> 2541 public Task<RedisScan<string>> ScanAsync(long cursor, string pattern = null, long? count = null) => NodesNotSupportAsync("ScanAsync", (c, k) => c.Value.ScanAsync(cursor, pattern, count)); 2542 /// <summary> 2543 /// 迭代当前数据库中的数据库键 2544 /// </summary> 2545 /// <typeparam name="T">byte[] 或其他类型</typeparam> 2546 /// <param name="cursor">位置</param> 2547 /// <param name="pattern">模式</param> 2548 /// <param name="count">数量</param> 2549 /// <returns></returns> 2550 async public Task<RedisScan<T>> ScanAsync<T>(long cursor, string pattern = null, long? count = null) 2551 { 2552 var scan = await NodesNotSupportAsync("ScanAsync<T>", (c, k) => c.Value.ScanBytesAsync(cursor, pattern, count)); 2553 return new RedisScan<T>(scan.Cursor, this.DeserializeRedisValueArrayInternal<T>(scan.Items)); 2554 } 2555 #endregion 2556 2557 #region Geo redis-server 3.2 2558 /// <summary> 2559 /// 将指定的地理空间位置(纬度、经度、成员)添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。 2560 /// </summary> 2561 /// <param name="key">不含prefix前辍</param> 2562 /// <param name="longitude">经度</param> 2563 /// <param name="latitude">纬度</param> 2564 /// <param name="member">成员</param> 2565 /// <returns>是否成功</returns> 2566 async public Task<bool> GeoAddAsync(string key, decimal longitude, decimal latitude, object member) => await GeoAddAsync(key, (longitude, latitude, member)) == 1; 2567 /// <summary> 2568 /// 将指定的地理空间位置(纬度、经度、成员)添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。 2569 /// </summary> 2570 /// <param name="key">不含prefix前辍</param> 2571 /// <param name="values">批量添加的值</param> 2572 /// <returns>添加到sorted set元素的数目,但不包括已更新score的元素。</returns> 2573 async public Task<long> GeoAddAsync(string key, params (decimal longitude, decimal latitude, object member)[] values) 2574 { 2575 if (values == null || values.Any() == false) return 0; 2576 var args = values.Select(z => (z.longitude, z.latitude, this.SerializeRedisValueInternal(z.member))).ToArray(); 2577 return await ExecuteScalarAsync(key, (c, k) => c.Value.GeoAddAsync(k, args)); 2578 } 2579 /// <summary> 2580 /// 返回两个给定位置之间的距离。如果两个位置之间的其中一个不存在, 那么命令返回空值。GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。 2581 /// </summary> 2582 /// <param name="key">不含prefix前辍</param> 2583 /// <param name="member1">成员1</param> 2584 /// <param name="member2">成员2</param> 2585 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2586 /// <returns>计算出的距离会以双精度浮点数的形式被返回。 如果给定的位置元素不存在, 那么命令返回空值。</returns> 2587 public Task<decimal?> GeoDistAsync(string key, object member1, object member2, GeoUnit unit = GeoUnit.m) 2588 { 2589 var args1 = this.SerializeRedisValueInternal(member1); 2590 var args2 = this.SerializeRedisValueInternal(member2); 2591 return ExecuteScalarAsync(key, (c, k) => c.Value.GeoDistAsync(k, args1, args2, unit)); 2592 } 2593 /// <summary> 2594 /// 返回一个或多个位置元素的 Geohash 表示。通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。 2595 /// </summary> 2596 /// <param name="key">不含prefix前辍</param> 2597 /// <param name="members">多个查询的成员</param> 2598 /// <returns>一个数组, 数组的每个项都是一个 geohash 。 命令返回的 geohash 的位置与用户给定的位置元素的位置一一对应。</returns> 2599 async public Task<string[]> GeoHashAsync(string key, object[] members) 2600 { 2601 if (members == null || members.Any() == false) return new string[0]; 2602 var args = members.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 2603 return await ExecuteScalarAsync(key, (c, k) => c.Value.GeoHashAsync(k, args)); 2604 } 2605 /// <summary> 2606 /// 从key里返回所有给定位置元素的位置(经度和纬度)。 2607 /// </summary> 2608 /// <param name="key">不含prefix前辍</param> 2609 /// <param name="members">多个查询的成员</param> 2610 /// <returns>GEOPOS 命令返回一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 而第二个元素则为给定位置元素的纬度。当给定的位置元素不存在时, 对应的数组项为空值。</returns> 2611 async public Task<(decimal longitude, decimal latitude)?[]> GeoPosAsync(string key, object[] members) 2612 { 2613 if (members == null || members.Any() == false) return new (decimal, decimal)?[0]; 2614 var args = members.Select(z => this.SerializeRedisValueInternal(z)).ToArray(); 2615 return await ExecuteScalarAsync(key, (c, k) => c.Value.GeoPosAsync(k, args)); 2616 } 2617 2618 /// <summary> 2619 /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。 2620 /// </summary> 2621 /// <param name="key">不含prefix前辍</param> 2622 /// <param name="longitude">经度</param> 2623 /// <param name="latitude">纬度</param> 2624 /// <param name="radius">距离</param> 2625 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2626 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2627 /// <param name="sorting">排序</param> 2628 /// <returns></returns> 2629 async public Task<string[]> GeoRadiusAsync(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2630 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusAsync(k, longitude, latitude, radius, unit, count, sorting, false, false, false))).Select(a => a.member).ToArray(); 2631 /// <summary> 2632 /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。 2633 /// </summary> 2634 /// <param name="key">不含prefix前辍</param> 2635 /// <param name="longitude">经度</param> 2636 /// <param name="latitude">纬度</param> 2637 /// <param name="radius">距离</param> 2638 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2639 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2640 /// <param name="sorting">排序</param> 2641 /// <returns></returns> 2642 async public Task<T[]> GeoRadiusAsync<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2643 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesAsync(k, longitude, latitude, radius, unit, count, sorting, false, false, false))).Select(a => this.DeserializeRedisValueInternal<T>(a.member)).ToArray(); 2644 2645 /// <summary> 2646 /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离)。 2647 /// </summary> 2648 /// <param name="key">不含prefix前辍</param> 2649 /// <param name="longitude">经度</param> 2650 /// <param name="latitude">纬度</param> 2651 /// <param name="radius">距离</param> 2652 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2653 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2654 /// <param name="sorting">排序</param> 2655 /// <returns></returns> 2656 async public Task<(string member, decimal dist)[]> GeoRadiusWithDistAsync(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2657 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusAsync(k, longitude, latitude, radius, unit, count, sorting, false, true, false))).Select(a => (a.member, a.dist)).ToArray(); 2658 /// <summary> 2659 /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离)。 2660 /// </summary> 2661 /// <param name="key">不含prefix前辍</param> 2662 /// <param name="longitude">经度</param> 2663 /// <param name="latitude">纬度</param> 2664 /// <param name="radius">距离</param> 2665 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2666 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2667 /// <param name="sorting">排序</param> 2668 /// <returns></returns> 2669 async public Task<(T member, decimal dist)[]> GeoRadiusWithDistAsync<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2670 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesAsync(k, longitude, latitude, radius, unit, count, sorting, false, true, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.dist)).ToArray(); 2671 2672 /// <summary> 2673 /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含经度、纬度)。 2674 /// </summary> 2675 /// <param name="key">不含prefix前辍</param> 2676 /// <param name="longitude">经度</param> 2677 /// <param name="latitude">纬度</param> 2678 /// <param name="radius">距离</param> 2679 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2680 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2681 /// <param name="sorting">排序</param> 2682 /// <returns></returns> 2683 async private Task<(string member, decimal longitude, decimal latitude)[]> GeoRadiusWithCoordAsync(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2684 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusAsync(k, longitude, latitude, radius, unit, count, sorting, true, false, false))).Select(a => (a.member, a.longitude, a.latitude)).ToArray(); 2685 /// <summary> 2686 /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含经度、纬度)。 2687 /// </summary> 2688 /// <param name="key">不含prefix前辍</param> 2689 /// <param name="longitude">经度</param> 2690 /// <param name="latitude">纬度</param> 2691 /// <param name="radius">距离</param> 2692 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2693 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2694 /// <param name="sorting">排序</param> 2695 /// <returns></returns> 2696 async private Task<(T member, decimal longitude, decimal latitude)[]> GeoRadiusWithCoordAsync<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2697 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesAsync(k, longitude, latitude, radius, unit, count, sorting, true, false, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.longitude, a.latitude)).ToArray(); 2698 2699 /// <summary> 2700 /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离、经度、纬度)。 2701 /// </summary> 2702 /// <param name="key">不含prefix前辍</param> 2703 /// <param name="longitude">经度</param> 2704 /// <param name="latitude">纬度</param> 2705 /// <param name="radius">距离</param> 2706 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2707 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2708 /// <param name="sorting">排序</param> 2709 /// <returns></returns> 2710 async public Task<(string member, decimal dist, decimal longitude, decimal latitude)[]> GeoRadiusWithDistAndCoordAsync(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2711 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusAsync(k, longitude, latitude, radius, unit, count, sorting, true, true, false))).Select(a => (a.member, a.dist, a.longitude, a.latitude)).ToArray(); 2712 /// <summary> 2713 /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离、经度、纬度)。 2714 /// </summary> 2715 /// <param name="key">不含prefix前辍</param> 2716 /// <param name="longitude">经度</param> 2717 /// <param name="latitude">纬度</param> 2718 /// <param name="radius">距离</param> 2719 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2720 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2721 /// <param name="sorting">排序</param> 2722 /// <returns></returns> 2723 async public Task<(T member, decimal dist, decimal longitude, decimal latitude)[]> GeoRadiusWithDistAndCoordAsync<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2724 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesAsync(k, longitude, latitude, radius, unit, count, sorting, true, true, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.dist, a.longitude, a.latitude)).ToArray(); 2725 2726 /// <summary> 2727 /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。 2728 /// </summary> 2729 /// <param name="key">不含prefix前辍</param> 2730 /// <param name="member">成员</param> 2731 /// <param name="radius">距离</param> 2732 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2733 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2734 /// <param name="sorting">排序</param> 2735 /// <returns></returns> 2736 async public Task<string[]> GeoRadiusByMemberAsync(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2737 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusByMemberAsync(k, member, radius, unit, count, sorting, false, false, false))).Select(a => a.member).ToArray(); 2738 /// <summary> 2739 /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。 2740 /// </summary> 2741 /// <param name="key">不含prefix前辍</param> 2742 /// <param name="member">成员</param> 2743 /// <param name="radius">距离</param> 2744 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2745 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2746 /// <param name="sorting">排序</param> 2747 /// <returns></returns> 2748 async public Task<T[]> GeoRadiusByMemberAsync<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2749 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesByMemberAsync(k, member, radius, unit, count, sorting, false, false, false))).Select(a => this.DeserializeRedisValueInternal<T>(a.member)).ToArray(); 2750 2751 /// <summary> 2752 /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离)。 2753 /// </summary> 2754 /// <param name="key">不含prefix前辍</param> 2755 /// <param name="member">成员</param> 2756 /// <param name="radius">距离</param> 2757 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2758 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2759 /// <param name="sorting">排序</param> 2760 /// <returns></returns> 2761 async public Task<(string member, decimal dist)[]> GeoRadiusByMemberWithDistAsync(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2762 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusByMemberAsync(k, member, radius, unit, count, sorting, false, true, false))).Select(a => (a.member, a.dist)).ToArray(); 2763 /// <summary> 2764 /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离)。 2765 /// </summary> 2766 /// <param name="key">不含prefix前辍</param> 2767 /// <param name="member">成员</param> 2768 /// <param name="radius">距离</param> 2769 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2770 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2771 /// <param name="sorting">排序</param> 2772 /// <returns></returns> 2773 async public Task<(T member, decimal dist)[]> GeoRadiusByMemberWithDistAsync<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2774 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesByMemberAsync(k, member, radius, unit, count, sorting, false, true, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.dist)).ToArray(); 2775 2776 /// <summary> 2777 /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含经度、纬度)。 2778 /// </summary> 2779 /// <param name="key">不含prefix前辍</param> 2780 /// <param name="member">成员</param> 2781 /// <param name="radius">距离</param> 2782 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2783 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2784 /// <param name="sorting">排序</param> 2785 /// <returns></returns> 2786 async private Task<(string member, decimal longitude, decimal latitude)[]> GeoRadiusByMemberWithCoordAsync(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2787 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusByMemberAsync(k, member, radius, unit, count, sorting, true, false, false))).Select(a => (a.member, a.longitude, a.latitude)).ToArray(); 2788 /// <summary> 2789 /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含经度、纬度)。 2790 /// </summary> 2791 /// <param name="key">不含prefix前辍</param> 2792 /// <param name="member">成员</param> 2793 /// <param name="radius">距离</param> 2794 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2795 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2796 /// <param name="sorting">排序</param> 2797 /// <returns></returns> 2798 async private Task<(T member, decimal longitude, decimal latitude)[]> GeoRadiusByMemberWithCoordAsync<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2799 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesByMemberAsync(k, member, radius, unit, count, sorting, true, false, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.longitude, a.latitude)).ToArray(); 2800 2801 /// <summary> 2802 /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离、经度、纬度)。 2803 /// </summary> 2804 /// <param name="key">不含prefix前辍</param> 2805 /// <param name="member">成员</param> 2806 /// <param name="radius">距离</param> 2807 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2808 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2809 /// <param name="sorting">排序</param> 2810 /// <returns></returns> 2811 async public Task<(string member, decimal dist, decimal longitude, decimal latitude)[]> GeoRadiusByMemberWithDistAndCoordAsync(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2812 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusByMemberAsync(k, member, radius, unit, count, sorting, true, true, false))).Select(a => (a.member, a.dist, a.longitude, a.latitude)).ToArray(); 2813 /// <summary> 2814 /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离、经度、纬度)。 2815 /// </summary> 2816 /// <param name="key">不含prefix前辍</param> 2817 /// <param name="member">成员</param> 2818 /// <param name="radius">距离</param> 2819 /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param> 2820 /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param> 2821 /// <param name="sorting">排序</param> 2822 /// <returns></returns> 2823 async public Task<(T member, decimal dist, decimal longitude, decimal latitude)[]> GeoRadiusByMemberWithDistAndCoordAsync<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) => 2824 (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesByMemberAsync(k, member, radius, unit, count, sorting, true, true, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.dist, a.longitude, a.latitude)).ToArray(); 2825 #endregion 2826 } 2827 } 2828 #endif
使用方式
在Startup中注入
在server中使用