csharp/17MKH/Mkh/src/05_Cache/Cache.Redis/RedisDatabase.cs

RedisDatabase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using StackExchange.Redis;

namespace Mkh.Cache.Redis;

/// 
/// 自定义的Redis数据库
/// 
public clast RedisDatabase
{
    private readonly IDatabase _db;
    private readonly RedisHelper _redisHelper;
    private readonly ConnectionMultiplexer _redis;
    private readonly IRedisSerializer _redisSerializer;
    private readonly int _dbIndex;

    public RedisDatabase(int dbIndex, RedisHelper redisHelper)
    {
        _dbIndex = dbIndex < 0 ? 0 : dbIndex;
        _redisHelper = redisHelper;
        _redis = redisHelper._redis;
        _redisSerializer = redisHelper._redisSerializer;
        _db = _redis.GetDatabase(_dbIndex);
    }

    private string GetKey(string key)
    {
        return _redisHelper.GetKey(key);
    }

    #region ==String==

    /// 
    /// 写入字符串类型
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 
    public Task StringSetAsync(string key, T obj, TimeSpan? expiry = null)
    {
        return _db.StringSetAsync(GetKey(key), _redisSerializer.Serialize(obj), expiry);
    }

    /// 
    /// 获取字符串类型
    /// 
    /// 
    /// 
    /// 
    public async Task StringGetAsync(string key)
    {
        var cache = await _db.StringGetAsync(GetKey(key));
        return cache.HasValue ? _redisSerializer.Deserialize(cache) : default;
    }

    /// 
    /// 字符串减去数值
    /// 
    /// 
    /// 
    /// 
    public Task StringDecrementAsync(string key, long value = 1)
    {
        return _db.StringDecrementAsync(GetKey(key), value);
    }

    /// 
    /// 字符串增加数值
    /// 
    /// 
    /// 
    /// 
    public Task StringIncrementAsync(string key, long value = 1)
    {
        return _db.StringIncrementAsync(GetKey(key), value);
    }

    #endregion

    #region ==Hash==

    /// 
    /// 设置值
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 
    public Task HashSetAsync(string key, string field, T obj)
    {
        return _db.HashSetAsync(GetKey(key), field, _redisSerializer.Serialize(obj));
    }

    /// 
    /// 获取值
    /// 
    /// 
    /// 
    /// 
    /// 
    public async Task HashGetAsync(string key, string field)
    {
        var cache = await _db.HashGetAsync(GetKey(key), field);
        return cache.HasValue ? _redisSerializer.Deserialize(cache) : default;
    }

    /// 
    /// 获取所有值
    /// 
    /// 
    /// 
    /// 
    public async Task HashValuesAsync(string key)
    {
        var cache = await _db.HashValuesAsync(GetKey(key));
        return cache.Any() ? cache.Select(_redisSerializer.Deserialize).ToList() : default;
    }

    /// 
    /// 删除值
    /// 
    /// 
    /// 
    /// 
    public Task HashDeleteAsync(string key, string field)
    {
        return _db.HashDeleteAsync(GetKey(key), field);
    }

    /// 
    /// 获取所有键值集合
    /// 
    /// 
    /// 
    /// 
    public async Task HashGetAllAsync(string key)
    {
        var cache = await _db.HashGetAllAsync(GetKey(key));
        return cache.Select(m => new KeyValuePair(m.Name.ToString(), _redisSerializer.Deserialize(m.Value))).ToList();
    }

    /// 
    /// 数值减
    /// 
    /// 
    /// 
    /// 
    /// 
    public Task HashDecrementAsync(string key, string field, long value = 1)
    {
        return _db.HashDecrementAsync(GetKey(key), field, value);
    }

    /// 
    /// 数值加
    /// 
    /// 
    /// 
    /// 
    /// 
    public Task HashIncrementAsync(string key, string field, long value = 1)
    {
        return _db.HashIncrementAsync(GetKey(key), field, value);
    }

    /// 
    /// 判断字段是否存在
    /// 
    /// 
    /// 
    /// 
    public Task HashExistsAsync(string key, string field)
    {
        return _db.HashExistsAsync(GetKey(key), field);
    }

    #endregion

    #region ==Set==

    public Task SetAddAsync(string key, T obj)
    {
        return _db.SetAddAsync(GetKey(key), _redisSerializer.Serialize(obj));
    }

    public Task SetRemoveAsync(string key, T obj)
    {
        return _db.SetRemoveAsync(GetKey(key), _redisSerializer.Serialize(obj));
    }

    public Task SetContainsAsync(string key, T obj)
    {
        return _db.SetContainsAsync(GetKey(key), _redisSerializer.Serialize(obj));
    }

    public Task SetLengthAsync(string key)
    {
        return _db.SetLengthAsync(GetKey(key));
    }

    public async Task SetPopAsync(string key)
    {
        var cache = await _db.SetPopAsync(GetKey(key));
        return cache.HasValue ? _redisSerializer.Deserialize(cache) : default;
    }

    public async Task SetMembersAsync(string key)
    {
        var cache = await _db.SetMembersAsync(GetKey(key));
        return cache.Any() ? cache.Select(_redisSerializer.Deserialize).ToList() : default;
    }

    #endregion

    #region ==Sorted Set==

    /// 
    /// 添加有序集合
    /// 
    /// 
    /// 
    /// 
    /// 
    public Task SortedSetAddAsync(string key, T member, double score)
    {
        return _db.SortedSetAddAsync(GetKey(key), _redisSerializer.Serialize(member), score);
    }

    /// 
    /// 减去值
    /// 
    /// 
    /// 
    /// 
    /// 
    public Task SortedSetDecrementAsync(string key, T member, double value)
    {
        return _db.SortedSetDecrementAsync(GetKey(key), _redisSerializer.Serialize(member), value);
    }

    /// 
    /// 增加值
    /// 
    /// 
    /// 
    /// 
    /// 
    public Task SortedSetIncrementAsync(string key, T member, double value)
    {
        return _db.SortedSetIncrementAsync(GetKey(key), _redisSerializer.Serialize(member), value);
    }

    /// 
    /// 获取排名的成员
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 
    public async Task SortedSetRangeByRankAsync(string key, long start = 0, long stop = -1, Order order = Order.Ascending)
    {
        var cache = await _db.SortedSetRangeByRankAsync(GetKey(key), start, stop, order);
        return cache.Select(_redisSerializer.Deserialize).ToList();
    }

    /// 
    /// 获取排名的成员和值
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 
    public async Task SortedSetRangeByRankWithScoresAsync(string key, long start = 0, long stop = -1, Order order = Order.Ascending)
    {
        var cache = await _db.SortedSetRangeByRankWithScoresAsync(GetKey(key), start, stop, order);
        return cache.Select(m => new KeyValuePair(_redisSerializer.Deserialize(m.Element), m.Score)).ToList();
    }

    /// 
    /// 返回指定分数区间的成员数量
    /// 
    /// 
    /// 
    /// 
    /// 
    public Task SortedSetLengthAsync(string key, double min = double.NegativeInfinity, double max = double.PositiveInfinity)
    {
        return _db.SortedSetLengthAsync(GetKey(key), min, max);
    }

    /// 
    /// 删除并返回第一个元素,默认情况下,分数是从低到高排序的。
    /// 
    /// 
    /// 
    /// 
    public async Task SortedSetPopAsync(string key, Order order = Order.Ascending)
    {
        var entry = await _db.SortedSetPopAsync(GetKey(key), order);
        return entry != null ? new KeyValuePair(_redisSerializer.Deserialize(entry.Value.Element), entry.Value.Score) : default;
    }

    /// 
    /// 删除指定成员
    /// 
    /// 
    /// 
    /// 
    public Task SortedSetRemoveAsync(string key, T member)
    {
        return _db.SortedSetRemoveAsync(GetKey(key), _redisSerializer.Serialize(member));
    }

    /// 
    /// 根据分数区间删除
    /// 
    /// 
    /// 
    /// 
    /// 删除数量
    public Task SortedSetRemoveRangeByScoreAsync(string key, long start = 0, long stop = -1)
    {
        return _db.SortedSetRemoveRangeByScoreAsync(GetKey(key), start, stop);
    }

    /// 
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 删除数量
    public Task SortedSetRemoveRangeByRankAsync(string key, long start = 0, long stop = -1)
    {
        return _db.SortedSetRemoveRangeByRankAsync(GetKey(key), start, stop);
    }

    #endregion

    #region ==KeyDelete==

    /// 
    /// 删除键
    /// 
    /// 
    /// 
    public bool KeyDelete(string key)
    {
        return _db.KeyDelete(GetKey(key));
    }

    /// 
    /// 删除键
    /// 
    /// 
    /// 
    public Task KeyDeleteAsync(string key)
    {
        return _db.KeyDeleteAsync(GetKey(key));
    }

    #endregion

    #region ==KeyExists==

    /// 
    /// 是否存在键
    /// 
    /// 
    /// 
    public bool KeyExists(string key)
    {
        return _db.KeyExists(GetKey(key));
    }

    /// 
    /// 是否存在键
    /// 
    /// 
    /// 
    public Task KeyExistsAsync(string key)
    {
        return _db.KeyExistsAsync(GetKey(key));
    }

    #endregion

    #region ==KeyExpire==

    /// 
    /// 设置过期时间
    /// 
    /// 
    /// 
    /// 
    public bool KeyExpire(string key, DateTime? expiry)
    {
        return _db.KeyExpire(GetKey(key), expiry);
    }

    /// 
    /// 设置过期时间
    /// 
    /// 
    /// 
    /// 
    public Task KeyExpireAsync(string key, DateTime? expiry)
    {
        return _db.KeyExpireAsync(GetKey(key), expiry);
    }

    /// 
    /// 设置过期时间
    /// 
    /// 
    /// 
    /// 
    public bool KeyExpire(string key, TimeSpan? expiry)
    {
        return _db.KeyExpire(GetKey(key), expiry);
    }

    /// 
    /// 设置过期时间
    /// 
    /// 
    /// 
    /// 
    public Task KeyExpireAsync(string key, TimeSpan? expiry)
    {
        return _db.KeyExpireAsync(GetKey(key), expiry);
    }

    #endregion

    #region ==Other==

    private IList GetKeys(string prefix = null, int pageSize = 10, int pageOffset = 0)
    {
        var pat = prefix.IsNull() ? null : $"{GetKey(prefix)}*";
        var endPoints = _redis.GetEndPoints();
        if (endPoints.Length > 1)
        {
            var skipNum = pageOffset * pageSize;
            var leftNum = skipNum + pageSize;
            var keys = new List();
            foreach (var endPoint in endPoints)
            {
                if (leftNum > 0)
                {
                    foreach (var key in _redis.GetServer(endPoint).Keys(_dbIndex, pat, pageSize: leftNum))
                    {
                        if (keys.Any(m => m == key))
                        {
                            continue;
                        }
                        keys.Add(key);
                        leftNum--;
                    }
                }
            }
            return keys.Skip(pageSize * pageOffset).Take(pageSize).ToList();
        }
        else
        {
            return _redis.GetServer(_redis.GetEndPoints().FirstOrDefault()).Keys(_dbIndex, pat, pageSize: pageSize, pageOffset: pageOffset).ToList();
        }
    }

    /// 
    /// 分页获取所有Keys
    /// 
    /// 
    /// 
    /// 
    public IList GetAllKeys(int pageSize = 10, int pageOffset = 0)
    {
        return GetKeys(pageSize: pageSize, pageOffset: pageOffset);
    }

    /// 
    /// 分页获取指定前缀的Keys列表
    /// 
    /// 
    /// 
    /// 
    /// 
    public IList GetKeysByPrefix(string prefix, int pageSize = 10, int pageOffset = 0)
    {
        if (prefix.IsNull())
            return new List();

        return GetKeys(prefix, pageSize, pageOffset);
    }

    /// 
    /// 删除指定前缀的Keys
    /// 
    /// 
    /// 
    public async Task DeleteByPrefix(string prefix)
    {
        var pageSize = 1000;
        var pageOffset = 0;
        var hasEnd = false;
        while (!hasEnd)
        {
            var keys = GetKeysByPrefix(prefix, pageSize, pageOffset);
            if (keys == null || !keys.Any())
            {
                hasEnd = true;
            }
            else
            {
                try
                {
                    await _db.KeyDeleteAsync(keys.ToArray());
                }
                catch (RedisCommandException ex)
                {
                    if (ex.Message.StartsWith("Multi-key operations must involve a single slot;"))
                    {
                        await Task.WhenAll(keys.Select(m => _db.KeyDeleteAsync(m)));
                    }
                    else
                    {
                        throw ex;
                    }
                }
            }
        }
    }

    #endregion
}