using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.Identity.Client; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using StackExchange.Redis; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using IDatabase = StackExchange.Redis.IDatabase; namespace HuanMeng.DotNetCore.Redis { /// /// 数据库连接字符串 /// public static class RedisConnection { /// /// 数据库连接 /// public static ConcurrentDictionary Redis { get; set; } = new ConcurrentDictionary(); /// /// 数据库查询 /// public static ConcurrentDictionary RedisServer { get; set; } = new ConcurrentDictionary(); /// /// /// /// /// public static IDatabase GetRedis(string redisConnection) { if (!Redis.TryGetValue(redisConnection, out var database)) { var redis = ConnectionMultiplexer.Connect(redisConnection); database = redis.GetDatabase(); //server.key //redis.GetServer() Redis.TryAdd(redisConnection, database); } return database; } /// /// /// /// /// public static IServer GetServer(string redisConnection) { if (!RedisServer.TryGetValue(redisConnection, out var server)) { var redis = ConnectionMultiplexer.Connect(redisConnection); var serverConn = ParseIpPortAndDatabase(redisConnection); server = redis.GetServer(serverConn.ip, serverConn.port); //server.key //redis.GetServer() RedisServer.TryAdd(redisConnection, server); } return server; } private static (string ip, int port, int database) ParseIpPortAndDatabase(string connectionString) { // 默认端口号和默认数据库 int defaultPort = 6379; int defaultDatabase = 0; if (string.IsNullOrEmpty(connectionString)) { return ("localhost", defaultPort, defaultDatabase); } // 按逗号分割,获取主机部分和其他参数 var parts = connectionString.Split(','); var hostPart = parts[0]; // 例如:"192.168.195.6:6379" // 检查是否包含端口号 string ip; int port; if (hostPart.Contains(":")) { var hostParts = hostPart.Split(':'); ip = hostParts[0]; port = int.TryParse(hostParts[1], out int parsedPort) ? parsedPort : defaultPort; } else { // 如果没有端口号,使用默认端口 ip = hostPart; port = defaultPort; } // 解析 defaultDatabase 参数 int database = defaultDatabase; foreach (var part in parts) { if (part.StartsWith("defaultDatabase=", StringComparison.OrdinalIgnoreCase)) { var dbPart = part.Split('='); if (dbPart.Length == 2 && int.TryParse(dbPart[1], out int parsedDb)) { database = parsedDb; } } } return (ip, port, database); } /// /// /// /// /// /// /// /// public static bool StringSetLock(this IDatabase database, string key, string value, int time = 10) { return database.StringSet(key, value, TimeSpan.FromSeconds(time), when: When.NotExists); } /// /// 删除key /// /// /// /// public static async Task KeysDeleteds(this IDatabase database, string key) { string luaScript = @" local keys = redis.call('KEYS', ARGV[1]) if next(keys) ~= nil then return redis.call('DEL', unpack(keys)) else return 0 end "; var keysDeleted = (int)await (database.ScriptEvaluateAsync(luaScript, values: new RedisValue[] { key })); return keysDeleted; } /// /// 获取一个key的对象 /// /// /// /// public static T? StringGet(this IDatabase database, string key) { var value = database.StringGet(key); // 检查值是否为空 if (!value.HasValue) { return default(T); } if (typeof(T).IsPrimitive || typeof(T) == typeof(string) || typeof(T) == typeof(decimal)) { try { return (T)Convert.ChangeType(value.ToString(), typeof(T)); } catch { return default; // 或抛出异常,取决于业务需求 } } // 将 RedisValue 转换为 T 类型 return JsonConvert.DeserializeObject(value); } /// /// 数据存放在redis /// /// /// /// /// /// public static async Task StringSetAsync(this IDatabase database, string key, object value, TimeSpan? expiry) { return await database.StringSetAsync(key, (value == null ? "" : JsonConvert.SerializeObject(value)), expiry, When.Always); } /// /// 数据存放在redis /// /// /// /// /// /// public static bool StringSet(this IDatabase database, string key, object value, TimeSpan? expiry = null) { return database.StringSet(key, (value == null ? "" : JsonConvert.SerializeObject(value)), expiry, When.Always); } /// /// 获取一个key的对象 /// /// /// /// public static async Task StringGetAsync(this IDatabase database, string key) { var value = await database.StringGetAsync(key); // 检查值是否为空 if (!value.HasValue) { return default(T); } if (typeof(T).IsPrimitive || typeof(T) == typeof(string) || typeof(T) == typeof(decimal)) { try { return (T)Convert.ChangeType(value.ToString(), typeof(T)); } catch { return default; // 或抛出异常,取决于业务需求 } } // 将 RedisValue 转换为 T 类型 return JsonConvert.DeserializeObject(value); } /// /// 模糊查询key /// /// /// /// /// public static List ScanKeys(this IServer server, string pattern, int pageSize = 1000) { var matchingKeys = server.Keys(pattern: pattern, pageSize: pageSize).Select(it => it.ToString()).ToList(); return matchingKeys; } /// /// 异步模糊查询key /// /// Redis 服务器实例 /// 匹配的模式(支持通配符) /// 每次扫描的页大小 /// 数据库编号,默认值为 -1 表示全部数据库 /// 匹配的键的字符串列表 public static async Task> ScanKeysAsync(this IServer server, string pattern, int pageSize = 1000, int database = -1) { var matchingKeys = new List(); try { await foreach (var key in server.KeysAsync(database: database, pattern: pattern, pageSize: pageSize)) { matchingKeys.Add(key.ToString()); } } catch (Exception ex) { // 可以记录日志或者处理异常 Console.WriteLine($"Error while scanning keys: {ex.Message}"); } return matchingKeys; } /// /// 模糊查询所有匹配的键的数量 /// /// Redis 服务器实例 /// 匹配的模式(支持通配符) /// 匹配的键的数量 public static int ScanKeysCount(this IServer server, string pattern, int database = -1) { int count = 0; long cursor = 0; // 游标,用于记录扫描进度 do { // 使用 Keys 方法进行分页查询 var keys = server.Keys(database: database, cursor: cursor, pattern: pattern, pageSize: 1000).ToArray(); // 累计匹配到的键的数量 count += keys.Length; // 如果还有更多键,则获取新的游标;否则,循环终止 cursor = keys.Length == 1000 ? 1 : 0; } while (cursor != 0); return count; } /// /// 异步模糊查询所有匹配的键的数量 /// /// Redis 服务器实例 /// 匹配的模式(支持通配符) /// 每次扫描的页大小 /// 数据库编号,默认为 -1 表示当前数据库 /// 匹配的键的数量 public static async Task ScanKeysCountAsync(this IServer server, string pattern, int pageSize = 1000, int database = -1) { int count = 0; // 异步遍历 KeysAsync await foreach (var key in server.KeysAsync(database: database, pattern: pattern, pageSize: pageSize)) { count++; } return count; } } }