Redis开发05:使用stackexchange.redis库对redis进行增删改查

一、安装第三方库

二、官网

StackExchange.Redis |通用型 redis 客户端

三、连接示例

 private static string redisConnectionString = "localhost:6379,defaultDatabase=0,allowAdmin=true,asyncTimeout=10000,password=123456789";

 private static string redisConnectionString = "localhost:6379,defaultDatabase=0,allowAdmin=true,asyncTimeout=10000";

四、封装:增删改查

public class RedisData
{
    /// <summary>
    /// 键(包含冒号前的内容)
    /// </summary>
    public string Key { get; set; }

    /// <summary>
    /// 键尾
    /// </summary>
    public string KeyTail { get; set; }

    /// <summary>
    /// 值(str)
    /// </summary>
    public string Value { get; set; }

    /// <summary>
    /// 值(List Set)
    /// </summary>
    public List<string> ListValue { get; set; } = new List<string>();

    /// <summary>
    /// 值(Hash,即Dictionary)
    /// </summary>
    public Dictionary<string, string> HashDictValue { get; set; } = new Dictionary<string, string>();

    /// <summary>
    /// 值(SortedSet)
    /// </summary>
    public Dictionary<string, double> SortedSetValue { get; set; } = new Dictionary<string, double>();

    /// <summary>
    /// 值类型[包含:字符串,列表,无序集合(Set),有序集合(SortedSet),哈希(字典),流]
    /// </summary>
    public RedisType ValueType { get; set; }

    /// <summary>
    /// 剩余过期时间(天)
    /// </summary>
    public int? TTLDays { get; set; }

    /// <summary>
    /// 剩余过期时间(分钟)
    /// </summary>
    public int? TTLMins { get; set; }

    /// <summary>
    /// 剩余过期时间(秒)
    /// </summary>
    public int? TTLSecs { get; set; }

    /// <summary>
    /// 到期时间
    /// </summary>

    public DateTime? ExpirationTime { get; set; }
    /// <summary>
    /// 查询时间
    /// </summary>
    public DateTime QueryTime { get; set; }
}

public class RedisConn
{
    public string address { get; set; } = "localhost";

    public int port { get; set; } = 6379;

    public int database { get; set; } = 0;

    public string pwd { get; set; }
}

public static class RedisExtension
{
    private static RedisConn Conn = new RedisConn();

    // 默认的 Redis 连接字符串
    private static string redisConnectionString
    {
        get => $"{Conn.address}:{Conn.port},defaultDatabase={Conn.database},allowAdmin=true,asyncTimeout=10000,password={Conn.pwd}";
        set
        {
            // 当连接字符串被修改时,我们需要重新初始化 Lazy<ConnectionMultiplexer> 以确保新的连接字符串生效
            _redis = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(value));
        }
    }

    // 使用 Lazy 实例化连接,连接字符串可以被动态修改
    private static Lazy<ConnectionMultiplexer> _redis = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(redisConnectionString));

    // 通过连接获取 Redis 数据库
    private static IDatabase db => _redis.Value.GetDatabase();

    // 获取 Redis 服务器实例
    private static IServer server => _redis.Value.GetServer(Conn.address, Conn.port);


    // 更新 Redis 连接字符串的方法
    public static (RedisConn Conn, string redisConnectionString) UpdateRedisConnectionString(string address, int port, int database,string pwd)
    {
        Conn.address = address;
        Conn.port = port;
        Conn.database = database;
        Conn.pwd = pwd;

        // 更新连接字符串
        redisConnectionString = $"{Conn.address}:{Conn.port},defaultDatabase={Conn.database},allowAdmin=true,asyncTimeout=10000,password={Conn.pwd}";
        return (Conn:Conn,redisConnectionString:redisConnectionString);
    }


    /// <summary>
    /// 【配置】尝试连接
    /// </summary>
    /// <param name="conn"></param>
    /// <returns></returns>
    public static async Task<bool> TryConnectAsync(RedisConn conn = null)
    {
        // 如果传入了新的连接字符串,更新 Redis 连接
        if (conn != null)
        {
            Conn = conn;
        }

        try
        {
            // 通过插入 测试 Redis 连接
            string testKey = Guid.NewGuid().ToString();
            await SaveAsync(testKey, testKey);
            await DeleteAsync(testKey);
            return true; // 连接成功
        }
        catch (Exception ex)
        {
            return false; // 连接失败
        }
    }

    /// <summary>
    /// 【配置】获取redis数据库
    /// </summary>
    /// <returns></returns>
    public static async Task<IDatabase> GetDB()
    {
        return db;
    }

    /// <summary>
    /// 【配置】获取所有有数据的数据库名称
    /// </summary>
    /// <returns></returns>
    public static async Task<List<string>> GetUsedDB()
    {
        // 获取数据库的键空间信息 本质是执行INFO keyspace
        var info = server.Info("keyspace");
        if (!info.Any())
        {
            return new List<string>();
        }
        var list = info[0].Select(x => x.Key.ToString()).ToList();
        return list;
    }

    /// <summary>
    /// 【配置】获取redis服务
    /// </summary>
    /// <returns></returns>
    public static async Task<IServer> GetServer()
    {
        return server;
    }

    /// <summary>
    /// 【查询】符合条件的键(默认不传查所有)
    /// </summary>
    /// <param name="pattern">示例查找分类可以传入:"Transport:*"</param>
    /// <returns></returns>
    public static List<string> GetKeys(string pattern = "")
    {
        if (string.IsNullOrEmpty(pattern))
        {
            return server.Keys().Select(x => x.ToString()).ToList();
        }
        return server.Keys(pattern: pattern).Select(x => x.ToString()).ToList();
    }

    /// <summary>
    /// 【查询】指定键的键值对信息
    /// </summary>
    /// <param name="key"></param>
    public static async Task<RedisData> GetByKeyAsync(string key)
    {
        if (await db.KeyExistsAsync(key)) // 键存在
        {
            var valueType = await db.KeyTypeAsync(key);
            var listValue = new List<string>();
            if (valueType == RedisType.List)
            {
                listValue = (await db.ListRangeAsync(key)).Select(x => x.ToString()).ToList();
            }
            else if (valueType == RedisType.Set)
            {
                listValue = (await db.SetMembersAsync(key)).Select(x => x.ToString()).ToList();
            }
            RedisData data = new RedisData()
            {
                Key = key,
                Value = valueType == RedisType.String ? (await db.StringGetAsync(key)).ToString() : "",
                ValueType = valueType,
                ListValue = listValue,
                SortedSetValue = valueType == RedisType.SortedSet ? (await db.SortedSetRangeByRankWithScoresAsync(key)).ToDictionary(x => x.Element.ToString(), x => x.Score) : new Dictionary<string, double>(),
                HashDictValue = valueType == RedisType.Hash ? (await db.HashGetAllAsync(key)).ToDictionary(x => x.Name.ToString(), x => x.Value.ToString()) : new Dictionary<string, string>(),
                KeyTail = key.Split(':').LastOrDefault(),
                QueryTime = DateTime.Now
            };
            var ttl = await db.KeyTimeToLiveAsync(key);
            if (ttl != null)
            {
                data.ExpirationTime = DateTime.Now.Add(ttl.Value);
                data.TTLDays = Convert.ToInt32(ttl.Value.TotalDays);
                data.TTLMins = Convert.ToInt32(ttl.Value.TotalMinutes);
                data.TTLSecs = Convert.ToInt32(ttl.Value.TotalSeconds);
            }
            return data;
        }
        return null;
    }

    /// <summary>
    /// 【查询】所有键的键值对信息
    /// </summary>
    /// <param name="key"></param>
    public static async Task<List<RedisData>> GetAllAsync()
    {
        var allKeys = GetKeys();
        var list = new List<RedisData>();
        foreach (var key in allKeys)
        {
            var data = await GetByKeyAsync(key);
            if (data != null)
            {
                list.Add(data);
            }
        }
        return list;
    }

    /// <summary>
    /// 【删除】指定键,只有在键存在时才删除
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public static async Task<bool> DeleteAsync(string key)
    {
        if (await db.KeyExistsAsync(key)) // 判断键是否存在
        {
            return await db.KeyDeleteAsync(key); // 如果存在,删除键
        }
        return false; // 如果键不存在,返回 false
    }

    /// <summary>
    /// 【自定义指令(仅支持简单的,没有空格的命令)】
    /// </summary>
    /// 示例输入:PING INFO(查看配置信息) FLUSHDB(删除当前数据库所有键值对)  FLUSHALL(删除所有数据库键值对)
    /// <returns></returns>
    public static async Task<string> SendCommandAsync(string command)
    {
        string result = "";
        try
        {
            result = (await db.ExecuteAsync(command)).ToString();
            return result; // 返回响应
        }
        catch (Exception ex)
        {

            return ex.Message.ToString();
        }

    }

    /// <summary>
    /// 【获取INFO配置信息】
    /// </summary>
    /// <returns></returns>
    public static async Task<Dictionary<string, string>> GetInfo()
    {
        var splitlabel = ":";
        var infos = await SendCommandAsync("INFO");
        var infosList = infos.Split().Where(x => x.Contains(splitlabel));
        var showdict = new Dictionary<string, string>();
        foreach (var item in infosList)
        {
            var key = item.Split(splitlabel)[0].Trim();
            var value = item.Split(splitlabel)[1].Trim();
            switch (key)
            {
                case "redis_version":
                    showdict["版本号"] = value;
                    break;
                case "redis_mode":
                    showdict["模式"] = value;
                    break;
                case "role":
                    showdict["角色"] = value;
                    break;
                case "process_id":
                    showdict["进程PID"] = value;
                    break;
                case "tcp_port":
                    showdict["TCP端口"] = value;
                    break;
                case "uptime_in_days":
                    showdict["服务已运行天数"] = value;
                    break;
                case "hz":
                    showdict["每秒执行操作数"] = value;
                    break;
                case "executable":
                    showdict["执行文件路径"] = value;
                    break;
                case "config_file":
                    showdict["配置文件路径"] = value;//executable
                    break;
                case "connected_clients":
                    showdict["当前连接数"] = value;
                    break;
                case "blocked_clients":
                    showdict["阻塞数量"] = value;
                    break;
                case "used_memory_human":
                    showdict["总使用内存"] = value;
                    break;
                case "used_memory_rss_human":
                    showdict["物理内存"] = value;
                    break;
                case "used_memory_peak_human":
                    showdict["峰值使用内存"] = value;
                    break;
                case "maxmemory_policy":
                    showdict["内存回收策略"] = value;
                    break;
                case "mem_fragmentation_ratio":
                    showdict["碎片比例"] = value;
                    break;
                case "mem_allocator":
                    showdict["内存分配器"] = value;
                    break;
                case "rdb_last_save_time":
                    showdict["RDB上次成功保存的时间"] = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt32(value)).LocalDateTime.ToString("yyyy年MM月dd日 HH时mm分ss秒");
                    break;
                case "rdb_last_bgsave_status":
                    showdict["RDB上次保存的状态"] = value;
                    break;
                case "aof_enabled":
                    showdict["是否启用 AOF 持久化"] = value;
                    break;
                case "expired_keys":
                    showdict["过期的键数量"] = value;
                    break;
                case "pubsub_channels":
                    showdict["当前的订阅频道数"] = value;
                    break;
                case "pubsub_patterns":
                    showdict["当前的订阅模式数"] = value;
                    break;
                case "latest_fork_usec":
                    showdict["最近一次 fork 操作的耗时(秒)"] = Math.Round(Convert.ToDouble(value) / 1000, 2).ToString();
                    break;
                case "cluster_enabled":
                    showdict["是否启用集群模式"] = value;
                    break;
                default:
                    break;
            }

        }
        return showdict;
    }


    /// <summary>
    /// 【保存】无论键是否存在,覆盖一个键值对(值:str)
    /// </summary>
    /// <param name="key">第一个入参示例“NewYork:School:John”(文件夹形式);第三个入参可以传递形如TimeSpan.FromSeconds(30),传null则表明永不过期</param>
    /// <param name="value"></param>
    /// <param name="expiration"></param>
    public static async Task<bool> SaveAsync(string key, string value, TimeSpan? expiration = null)
    {
        if (expiration == null) // 不设置超时时间
        {
            await db.StringSetAsync(key, value);
        }
        else // 设置超时时间
        {
            await db.StringSetAsync(key, value, expiration);
        }
        return true;
    }

    /// <summary>
    /// 【保存】无论键是否存在,覆盖一个键值对(值:List)
    /// </summary>
    /// <param name="key"></param>
    /// <param name="values"></param>
    /// <returns></returns>
    public static async Task<bool> ListRPUSH(string key, List<string> values)
    {
        long affectCounts = 0;
        foreach (var value in values)
        {
            affectCounts = await db.ListRightPushAsync(key, value); // 使用 ListRightPushAsync 向列表右端插入
        }
        return Convert.ToInt32(affectCounts) == values.Count;
    }

    /// <summary>
    /// 【保存】无论键是否存在,覆盖一个键值对(值:无序集合Set)
    /// </summary>
    /// <param name="key"></param>
    /// <param name="values"></param>
    /// <returns></returns>
    public static async Task<bool> SetSADD(string key, HashSet<string> values)
    {
        int addedCount = 0;

        foreach (var value in values)
        {
            bool wasAdded = await db.SetAddAsync(key, value);
            if (wasAdded || await GetByKeyAsync(value) != null)//如果被添加了或者存在,则都计入有效
            {
                addedCount++;
            }
        }

        // 添加数量=传入数量,则说明添加成功
        return addedCount == values.Count;
    }


    /// <summary>
    /// 【保存】无论键是否存在,覆盖一个键值对(值:有序集合SortedSet,其中值又分为键值对,值的键值对有两种模式:①全覆盖-默认 ②有该键不更新)
    /// </summary>
    /// <param name="key"></param>
    /// <param name="values"></param>
    /// <returns></returns>
    public static async Task<(int AddCount, int UnAddCount, int UnCoverCount)> SortedSetZADD(string key, Dictionary<string, double> dict, bool isCover = true)
    {
        int AddCount = 0;
        int UpdateCount = 0;
        int UnCoverCount = 0;
        var keys = (await GetByKeyAsync(key))?.SortedSetValue?.Select(x => x.Key).ToList();

        foreach (var kvp in dict)
        {
            if (!isCover && keys.Contains(kvp.Key))//选择模式2且有序集合的key是重复的
            {
                UnCoverCount++;
                continue;//不覆盖更新
            }
            bool wasAdded = await db.SortedSetAddAsync(key, kvp.Key, kvp.Value);
            if (wasAdded)
            {
                AddCount++;
            }
            else
            {
                UpdateCount++;
            }
        }

        return (AddCount: AddCount, UpdateCount: UpdateCount, UnCoverCount: UnCoverCount);//返回:插入数  更新数  未覆盖数
    }


    /// <summary>
    /// 【保存】无论键是否存在,覆盖一个键值对(值:哈希字典Hast-Dict)
    /// </summary>
    /// <param name="key"></param>
    /// <param name="values"></param>
    /// <returns></returns>
    public static async Task<bool> HashHSet(string key, Dictionary<string, string> dict, bool isCover = true)
    {
        try
        {
            HashEntry[] hashEntries = new HashEntry[dict.Count];
            int index = 0;
            foreach (var kvp in dict)
            {
                hashEntries[index++] = new HashEntry(kvp.Key, kvp.Value);
            }
            await db.HashSetAsync("myHash", hashEntries);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

    /// <summary>
    /// 【更新】设置指定键的过期时间[第二个入参可以传递形如TimeSpan.FromSeconds(30),传null则表明永不过期]
    /// </summary>
    public static async Task<bool> SetTTLAsync(string key, TimeSpan? expiration = null)
    {
        if (expiration == null)
        {
            return await db.KeyExpireAsync(key, (TimeSpan?)null); 
        }
        return await db.KeyExpireAsync(key, expiration);
    }

    /// <summary>
    /// 初始化测试数据
    /// </summary>
    /// <returns></returns>
    public static async Task<string> InitailTestData()
    {
        try
        {
            //初始化前先清空
            await RedisExtension.DeleteAsync("myList");
            await RedisExtension.DeleteAsync("myString");
            await RedisExtension.DeleteAsync("mySet");
            await RedisExtension.DeleteAsync("mySortedSet");
            await RedisExtension.DeleteAsync("myHash");
            await RedisExtension.DeleteAsync("Transport:bike");
            await RedisExtension.DeleteAsync("Transport:bus");
            await RedisExtension.DeleteAsync("Transport:metro:Line1");
            await RedisExtension.DeleteAsync("Transport:metro:Line2");
            await RedisExtension.DeleteAsync("Transport:high-speed-rail");

            //初始化一个字符串
            await RedisExtension.SaveAsync("myString", "2024888");

            //初始化字符串(带文件夹)
            await RedisExtension.SaveAsync("Transport:bike", "i am a bike");
            await RedisExtension.SaveAsync("Transport:bus", "i am a bus");
            await RedisExtension.SaveAsync("Transport:metro:Line1", "i am a metro Line1");
            await RedisExtension.SaveAsync("Transport:metro:Line2", "i am a metro Line2");
            await RedisExtension.SaveAsync("Transport:high-speed-rail", "i am a high-speed rail");


            //初始化一个列表List
            List<string> values = new List<string> { "item1", "item2", "item3" };
            await RedisExtension.ListRPUSH("myList", values);

            //初始化一个无序集合Set
            HashSet<string> values2 = new HashSet<string> { "apple", "banana", "cherry" };
            await RedisExtension.SetSADD("mySet", values2);

            //初始化一个有序集合SortedSet
            var players = new Dictionary<string, double>
                {
                    { "player1", 120 },
                    { "player2", 100 },
                    { "player3", 15 },
                    { "player4", 150 }
                };
            await RedisExtension.SortedSetZADD("mySortedSet", players);


            // 初始化一个哈希字典
            var myDict = new Dictionary<string, string>
            {
                { "name", "John" },
                { "age", "12" },
                { "city", "New York" }
            };
            await RedisExtension.HashHSet("myHash", myDict);

            //查询上面的所有数据
            var t1 = await RedisExtension.GetByKeyAsync("myList");
            var t2 = await RedisExtension.GetByKeyAsync("myString");
            var t3 = await RedisExtension.GetByKeyAsync("mySet");
            var t4 = await RedisExtension.GetByKeyAsync("mySortedSet");
            var t5 = await RedisExtension.GetByKeyAsync("myHash");

            return "初始化成功!";
        }
        catch (Exception ex)
        {
            return ex.ToString();
        }

    }
}

五、测试和运行demo

using ConsoleApp2;
using StackExchange.Redis;
using System;
using System.Collections.Generic;

class Program
{

    public static async Task<object> RunMain()
    {
        await RedisExtension.TryConnectAsync(new RedisConn
        {
            database = 1 //测试数据库
        });
        var res= await RedisExtension.InitailTestData();
        Console.WriteLine(res);
        return null;
    }
    
    static void Main(string[] args)
    {
        var t = Task.Run(async () =>await RunMain()).Result;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值