/* 作用: redis操作类 时间: 2023.06.09 作者: evangeyu 说明: 导出所有redis相关操作 使用约束: 1. 不允许大key,key命名包含唯一id: 数据库功能:类型:唯一id1 : 唯一id2:.... = 数据 如:AccountInfo:string:accountType:accountType = "xxx" 2. key禁止包含特殊字符,如空格、换行、单双引号以及其他转义字符 3. 如果是String类型,单个value大小控制10k以内 4. hash、list、set、zset类型,元素个数一般不超过5000 */ using System; using StackExchange.Redis; using Newtonsoft.Json; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Sog { public class RedisDB { private string m_dbName; private string m_ip; private static ConfigurationOptions m_connectConfig = null; private static ConnectionMultiplexer m_redisConn = null; private IDatabase m_redisDB { get { return m_redisConn.GetDatabase(); } } public RedisDB(string dbname, string ip, string password) { m_ip = ip; m_dbName = dbname; m_connectConfig = ConfigurationOptions.Parse(string.Format("{0},password={1}", ip, password)); m_connectConfig.CommandMap = CommandMap.Create(new HashSet { "SUBSCRIBE" }, false); // 禁用订阅功能 try { m_redisConn = ConnectionMultiplexer.Connect(m_connectConfig); RegisterEvent(); } catch (Exception ex) { TraceLog.Error("connect redis ip {0} error!", m_ip); TraceLog.Exception(ex); TraceLog.Error("Inner exception:"); TraceLog.Exception(ex.InnerException); } } public void Dispose() { if (m_redisConn != null) { m_redisConn.Close(true); m_redisConn.Dispose(); m_redisConn = null; } } public TimeSpan Ping() { return m_redisDB.Ping(); } public string CreateKey(string name, params string[] ids) { if (ids == null) { return string.Format("{0}:{1}", m_dbName, name);; } return string.Format("{0}:{1}:{2}", m_dbName, name, string.Join(":", ids)); } //----------------------------------------- 序列化 public static string ConvertToStr(T value) { return value is string ? value.ToString() : JsonConvert.SerializeObject(value); } public static T ConvertToObj(string value) { if (string.IsNullOrEmpty(value)) { return default(T); } else { return JsonConvert.DeserializeObject(value); } } private static List ConvetList(RedisValue[] values) { List result = new List(); foreach (var item in values) { var model = ConvertToObj(item); if (model != null) result.Add(model); } return result; } //----------------------------------------- String public bool StringSet(string redisKey, T obj) { return m_redisDB.StringSet(redisKey, ConvertToStr(obj)); } public T StringGet(string redisKey) { return ConvertToObj(m_redisDB.StringGet(redisKey)); } public long StringIncrement(string redisKey) { return m_redisDB.StringIncrement(redisKey); } public async Task StringSetAsync(string redisKey, T obj) { return await m_redisDB.StringSetAsync(redisKey, ConvertToStr(obj)); } public async Task StringGetAsync(string redisKey) { return ConvertToObj(await m_redisDB.StringGetAsync(redisKey)); } //----------------------------------------- Hash public void HashSetPart(string redisKey, IEnumerable hashFields) { m_redisDB.HashSet(redisKey, hashFields.ToArray()); } public RedisValue[] HashGetPart(string redisKey, RedisValue[] hashField) { return m_redisDB.HashGet(redisKey, hashField); } public bool HashSet(string redisKey, string hashField, T value) { return m_redisDB.HashSet(redisKey, hashField, ConvertToStr(value)); } public T HashGet(string redisKey, string hashField) { return ConvertToObj(m_redisDB.HashGet(redisKey, hashField)); } public HashEntry[] HashGetAll(string redisKey) { return m_redisDB.HashGetAll(redisKey); } public async Task HashGetAsync(string redisKey, string hashField) { return ConvertToObj(await m_redisDB.HashGetAsync(redisKey, hashField)); } public async Task HashSetAsync(string redisKey, string hashField, T value) { return await m_redisDB.HashSetAsync(redisKey, hashField, ConvertToStr(value)); } //----------------------------------------- List public string ListLeftPop(string redisKey) { return m_redisDB.ListLeftPop(redisKey); } public string ListRightPop(string redisKey) { return m_redisDB.ListRightPop(redisKey); } public long ListRemove(string redisKey, string redisValue, long count = 0) { return m_redisDB.ListRemove(redisKey, redisValue, count); } public void ListTrim(string redisKey, long start, long stop) { m_redisDB.ListTrim(redisKey, start, stop); } public void ListMaxLen(string redisKey, long maxLen) { ListTrim(redisKey, 0, maxLen > 0 ? (maxLen - 1) : -1); } public long ListRightPush(string redisKey, string redisValue) { return m_redisDB.ListRightPush(redisKey, redisValue); } public long ListLeftPush(string redisKey, string redisValue) { return m_redisDB.ListLeftPush(redisKey, redisValue); } public long ListLength(string redisKey) { return m_redisDB.ListLength(redisKey); } public IEnumerable ListRange(string redisKey, int startRow=0, int endRow=-1) { return m_redisDB.ListRange(redisKey, startRow, endRow); } public long ListRightPush(string redisKey, T value) { return m_redisDB.ListRightPush(redisKey, ConvertToStr(value)); } public long ListLeftPush(string redisKey, T value) { return m_redisDB.ListLeftPush(redisKey, ConvertToStr(value)); } public List ListRange(string redisKey, int startRow=0, int endRow=-1) { return ConvetList(ListRange(redisKey, startRow, endRow).ToArray()); } //----------------------------------------- Set public bool SetAdd(string redisKey, string member) { return m_redisDB.SetAdd(redisKey, member); } public long SetAdd(string redisKey, RedisValue[] members) { return m_redisDB.SetAdd(redisKey, members); } public long SetLength(string redisKey) { return m_redisDB.SetLength(redisKey); } public bool SetRemove(string redisKey, string memebr) { return m_redisDB.SetRemove(redisKey, memebr); } public bool SetAdd(string redisKey, T member) { return m_redisDB.SetAdd(redisKey, ConvertToStr(member)); } public RedisValue[] SetMembers(string redisKey) { return m_redisDB.SetMembers(redisKey); } //----------------------------------------- SortedSet public bool ZSetAdd(string redisKey, string member, double score) { return m_redisDB.SortedSetAdd(redisKey, member, score); } public IEnumerable ZSetRangeByRank(string redisKey) { return m_redisDB.SortedSetRangeByRank(redisKey); } public long ZSetLength(string redisKey) { return m_redisDB.SortedSetLength(redisKey); } public bool ZSetRemove(string redisKey, string memebr) { return m_redisDB.SortedSetRemove(redisKey, memebr); } public bool ZSetAdd(string redisKey, T member, double score) { return m_redisDB.SortedSetAdd(redisKey, ConvertToStr(member), score); } public IEnumerable ZSetScan(string redisKey, string pattern, int pageSize = 250, long cursor = 0, int pageOffset = 0) { return m_redisDB.SortedSetScan(redisKey, pattern, pageSize, cursor, pageOffset); } //----------------------------------------- 操作key public bool KeyDelete(string redisKey) { return m_redisDB.KeyDelete(redisKey); } public long KeyDelete(IEnumerable redisKeys) { var keys = redisKeys.Select(x => (RedisKey)x); return m_redisDB.KeyDelete(keys.ToArray()); } public bool KeyExists(string redisKey) { return m_redisDB.KeyExists(redisKey); } public bool KeyRename(string redisKey, string redisNewKey) { return m_redisDB.KeyRename(redisKey, redisNewKey); } public bool KeyExpire(string redisKey, TimeSpan? expiry) { return m_redisDB.KeyExpire(redisKey, expiry); } //----------------------------------------- keys scan // 注意:这个底层可能使用了keys 和 scan两种命令 // pattern : 支持通配符 (*:任意字符;?:单个任意字符;[ab]:指定范围内的字符) public IEnumerable Keys(RedisValue _pattern = default) { var server = m_redisConn.GetServer(m_ip); return server.Keys(pattern: _pattern); } // pattern : 支持通配符 (*:任意字符;?:单个任意字符;[ab]:指定范围内的字符) public long Scan(ref IEnumerable result, string _pattern, long cursor = 0, int count = 100) { var redisResults = (RedisResult[])m_redisDB.Execute("scan", cursor, "MATCH", _pattern, "COUNT", count); result = (RedisKey[])redisResults[1]; return (long)redisResults[0]; } //----------------------------------------- pipleline 批处理 public IBatch CreateBatch() { return m_redisDB.CreateBatch(); } //----------------------------------------- redis相关事件 private static void RegisterEvent() { m_redisConn.ConfigurationChangedBroadcast += OnConfigurationChangedBroadcast; m_redisConn.HashSlotMoved += OnHashSlotMoved; m_redisConn.ConfigurationChanged += OnConfigurationChanged; m_redisConn.ConnectionRestored += OnConnectionRestored; m_redisConn.ConnectionFailed += OnConnectionFailed; m_redisConn.ErrorMessage += OnErrorMessage; m_redisConn.InternalError += OnInternalError; } // 重新配置广播-主从同步更改 private static void OnConfigurationChangedBroadcast(object sender, EndPointEventArgs e) { TraceLog.Trace($"{nameof(OnConfigurationChangedBroadcast)}: {e.EndPoint}"); } // 更改集群 private static void OnHashSlotMoved(object sender, HashSlotMovedEventArgs e) { TraceLog.Error( $"{nameof(OnHashSlotMoved)}: {nameof(e.OldEndPoint)}-{e.OldEndPoint} To {nameof(e.NewEndPoint)}-{e.NewEndPoint}, "); } // 更改配置 private static void OnConfigurationChanged(object sender, EndPointEventArgs e) { TraceLog.Error($"{nameof(OnConfigurationChanged)}: {e.EndPoint}"); } // 连接失败 private static void OnConnectionFailed(object sender, ConnectionFailedEventArgs e) { TraceLog.Error($"{nameof(OnConnectionFailed)}: {e.Exception}"); } // 重新连接 private static void OnConnectionRestored(object sender, ConnectionFailedEventArgs e) { TraceLog.Error($"{nameof(OnConnectionRestored)}: {e.Exception}"); } // 发生错误 private static void OnErrorMessage(object sender, RedisErrorEventArgs e) { TraceLog.Error($"{nameof(OnErrorMessage)}: {e.Message}"); } // 内部错误 private static void OnInternalError(object sender, InternalErrorEventArgs e) { TraceLog.Error($"{nameof(OnInternalError)}: {e.Exception}"); } } }