悉野小楼

导航

C# redis操作(StackExchange.Redis )

参考:https://www.cnblogs.com/wzh2010/p/17205387.html

参考:https://www.runoob.com/redis/redis-keys.html

测试redis, 使用StackExchange.Redis 的api, 实现发布/订阅,  存放值,  分布式锁, 排序

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using StackExchange.Redis;

namespace RedisTest
{
    struct Msg
    {
        public string chanel;
        public byte[] msg;

        public Msg(string chanel, byte[] msg)
        {
            this.chanel = chanel;
            this.msg = msg;
        }
    }

    public partial class Form1 : Form
    {
        ConnectionMultiplexer redisClient = ConnectionMultiplexer.Connect("127.0.0.1:6359,allowadmin=true,password=12345,keepAlive=180");
        ISubscriber m_subscriber;
        IDatabase m_database;
        Queue<Msg> m_msgQueue = new Queue<Msg>();
        bool m_Closed = false;
        private ManualResetEvent m_ManualResetEvent = new ManualResetEvent(false);

        public Form1()
        {
            InitializeComponent();
        }

        private void DoJob()
        {
            while (true)
            {
                if (m_msgQueue.Count == 0)
                {
                    m_ManualResetEvent.WaitOne();
                    if(m_Closed)
                    {
                        break;
                    }
                }
                else
                {
                    Action action = () =>
                    {
                        var msg = m_msgQueue.Dequeue();
                        string str = UTF8Encoding.UTF8.GetString(msg.msg);
                        this.txtResult.Text += "chanel:"  + msg.chanel + "," + str + "\r\n";
                    };
                    this.txtResult.Invoke(action);
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(DoJob);
            thread.Start();
            
            //127.0.0.1:6379,allowadmin=true,password=12345,keepAlive=180
            // 设置订阅
            m_subscriber = redisClient.GetSubscriber();
            // 设置数据库
            m_database = redisClient.GetDatabase(0);

            m_subscriber.Subscribe("testchanel", (chanel, message)=>{
                m_msgQueue.Enqueue(new Msg(chanel, message));
                m_ManualResetEvent.Set();
            });

            /*
            m_subscriber.Subscribe("bb", (chanel, message) => {
                // lamda表达式转delegate
                Action action = () =>
                {
                    this.txtResult.Text += "chanel:" + chanel + "," + message + "\r\n";
                };
                this.txtResult.Invoke(action);
            });
            */
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string str = this.txtSend.Text + DateTime.Now.Ticks;
            m_subscriber.Publish("testchanel", str);
            /*
            byte[] bytes = System.Text.UTF8Encoding.UTF8.GetBytes(str);
            m_subscriber.Publish("bb", bytes);
            */
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            m_Closed = true;
            m_ManualResetEvent.Set();
        }

        private void btnSaveLoad_Click(object sender, EventArgs e)
        {
            // 参考:https://www.cnblogs.com/wzh2010/p/17205387.html
            // 参考:https://www.runoob.com/redis/redis-keys.html
            // 这个可以用来做分布式锁, 设置某个键, 并加超时时间, 并且可以设置只有不存在时才处理
            // SETNX 是 set if not exists 的缩写,当且仅当 key 不存在时,则设置 value 给这个key。若给定的 key 已经存在,则 SETNX 不做任何动作。
            // 命令的返回值说明:1:说明该进程获得锁,将 key 的值设为 value 0:说明其他进程已经获得了锁,进程不能进入临界区。

            // SET lock.user_063105015 1 NX PX 60000
            // NX:就是Not Exist,表示只有用户编号为 063105015 不存在的时候才可以 SET 成功,并且只有单个线程可以获取锁;
            // PX 60000:表示对这个锁设置一个60s的过期时间。
            bool ret = m_database.StringSet("mykeystring", 33, new TimeSpan(0, 0, 5), When.NotExists);

            m_database.SetAdd("myset", "set1");
            m_database.SetAdd("myset", "set2");
            m_database.ListRightPush("mylist", 1);
            m_database.ListRightPush("mylist", 2);

            // 可以使用StringGetSet, 取出旧值, 设置新值
            // 对应redis, GetSet命令, 可以使用这个来实现 分布式锁, 返回原来的值, 并且设置新的值
            // 下面的例子, 可以在拿的值判断拿到的值是否为1, 如果为1, 则说明被其它人设置了, 如果不是1, 则说明没被其它人操作,
            // 操作完删除key, 或更新成其它值
            var val = m_database.StringGetSet("myGetSetKey", 1);
            // 这个是给key加个超时, 防止程序异常中断, 死锁 对应redis EXPIRE key seconds, expire key 时间戳

            // GETEX命令同样也是Redis 6.2.0中新增的命令,它用于获取指定键值对的值,并设置或移除该键值对的过期时间。
            // 这儿测试时用的3.几的reids, 下面执行不了
            // 
            //var val2 = m_database.StringGetSetExpiry("myGetSetKey", new TimeSpan(0, 0, 3));
            
            m_database.StringAppend("mystring", "str1");
            m_database.StringAppend("mystring", "str2");
            var entery1 = new HashEntry("a", 1);
            var entery2 = new HashEntry("b", 2);
            m_database.HashSet("myhashkey", new HashEntry[] { entery1, entery2 });

            //redis zset排序
            m_database.SortedSetAdd("myzset", "", 8);
            m_database.SortedSetAdd("myzset", "", 9);
            m_database.SortedSetAdd("myzset", "", 7);
            long? rank = m_database.SortedSetRank("myzset", ""); //这儿返回0, 第一名
        }
    }
}

 下载测试代码

posted on 2023-10-30 10:52  悉野  阅读(270)  评论(0编辑  收藏  举报