StackExchange.Redis在net中使用


redis 官網 https://redis.io

 

redis 下載  進入下載頁面  https://redis.io/download

 https://github.com/MicrosoftArchive/redis/releases

單擊 Learn more 進入GitHub頁面

 

 

 

 github地址: https://github.com/antirez/redis

然后:

 

 

 

 

這里只有64位的。下載msi。安裝后。就可以在服務看到redis服務了

RedisDesktopManager 管理工具下載 https://redisdesktop.com/download

 https://github.com/uglide/RedisDesktopManager/releases/tag/0.8.8

https://github.com/uglide/RedisDesktopManager

 

 

net客戶端使用redis 一般都是使用 StackExchange.Redis 和 ServiceStack.Redis

SE是免費的。SS是收費的。這兩個dll都能通過NuGet安裝

 

既然SE是免費的。所以本文就使用SE.。

Redis簡介(收集網絡)

Remote Dictionary Server(Redis這個名稱是一個縮寫)是一個基於 key-value 鍵值對的、可以持久化的、完全開源免費的、遵守BSD協議的內存數據庫存儲系統,常用作緩存或者消息隊列。支持多種數據結構,包括 string (字符串)、list (鏈表)、set (集合)、zset (sorted set:有序集合)和 hash(哈希類型)。這些數據類型都支持 push/pop、add/remove 及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。
    
    接下來,我們在說說Redis的優勢的,如果沒有優勢,鬼才會使用它呢。    

1、讀寫性能極高 – Redis讀的速度是110000次/s,寫的速度是81000次/s,所以使用Redis緩存數據,存取數據幾乎是0感覺,當然是對於用戶來說的 。

    2、支持豐富的數據類型 – Redis支持豐富的數據類型,如: String(字符串), Lists(鏈表), Hash(哈希),Set(無序集合) 及 ZSet(有序集合)等數據類型,所以我們放棄了Memched,因為它支持的數據類型太少了。

    3、所有操作支持原子性 – Redis的所有操作都是原子性的,意思就是要么成功執行,要么失敗。單個操作是原子性的。多個操作也支持事務,即原子性,通過MULTI和EXEC指令包起來。

    4、豐富的特性 – Redis支持 publish/subscribe(發布/訂閱),也支持事務、隊列、持久化,可以設置key過期時間等等特性。

 

准備工作

導入dll后,創建一個單列

/// <summary>
    /// 單列
    /// </summary>
    public class RedisManager
    {
        private RedisManager() { }
        private static ConnectionMultiplexer instance;
private static readonly object locker = new object();
/// <summary> /// 單例模式獲取redis連接實例 /// </summary> public static ConnectionMultiplexer Instance { get {
        lock (locker)
        {
if (instance == null) { if (instance == null) instance = ConnectionMultiplexer.Connect("127.0.0.1"); //這里應該配置文件,不過這里演示就沒寫 }
        }
return instance; } } }

 

打開RedisDesktopManager 工具

RedisDesktopManager文檔:http://docs.redisdesktop.com/en/latest/quick-start/

 

 

 

String(字符串)

如果RedisKey 存在,則會替換

var db = RedisManager.Instance.GetDatabase();
var result = db.StringSet("string", "字符串"); //插入成功,返回true
db.StringGet("string") //獲取值

 

存json也可以

 

 

StringAppend 追加字符串

 db.StringAppend("string", "追加");

 

 

 

List (列表

 

特點:有序排列,值可以重復。我們可以通過pop,push操作來從頭部和尾部刪除或者添加元素。這使得list既可以做棧也可以做隊列

主要有:

ListRightPush:底部插入數據

ListLeftPush:頂部插入數據

ListLeftPop:出棧一條數據,出一條。則redis中就少一條

ListRightPop:同理

 

首先看看ListRightPush 方法,在list_right 中添加10條數據

 

for (int i = 0; i < 10; i++)
{
    db.ListRightPush("list_right", i);
 }

 

 

 

 

 

 

 ListLeftPush 方法:

for (int i = 0; i < 10; i++)
            {
                db.ListLeftPush("list_left", i);
            }

 

 

 

 如果有個需求,要顯示3個最后來的用戶,可以用ListLeftPush 方法。

只要3個,則可以用ListTrim 方法

db.ListTrim("list_left", 0, 2); //只顯示前3個

 

看看pop方法。比如ListRightPop

db.ListRightPop("list_left");

從底部出棧一條數據

 

 

來看看獲取List數據,獲取不是pop操作

 

 

 

 刪除一個鍵可以用 db.KeyDelete("list_right");

 

set(無序排列)

 

db.SetAdd("set_add", "你好");
db.SetAdd("set_add","小明");

 

 

 set提供了取並集,交集,差集的方法

SetCombine方法

RedisValue[] ds = db.SetCombine(SetOperation.Union, "set_add", "set_add");
            foreach (var item in ds.OrderBy(m => m).ToList())
            {
                Console.Write((string)item + "  ");
            }

 

SortedSet(有序排列)

添加順序不同,但最后會排序

 db.SortedSetAdd("sort", "t1",2);
            db.SortedSetAdd("sort", "t2", 12);
            db.SortedSetAdd("sort", "t3", 5);

 

 

SortedSet方法提供了累加的方法SortedSetIncrement

如果key和value都存在則累加。否則則新增

 db.SortedSetIncrement("sort", "t1", 8);//t1存在,則累加
            db.SortedSetIncrement("sort", "t4", 5); //t4不存在,則新增

 

可以看到。如果Score相同。則根據value排序

 

獲取key的話。通過SortedSetRangeByRank方法,該方法可以排序。通過Order.Ascending,

還可以從指定位置獲取

獲取key后。通過SortedSetScore 獲取Score

  RedisValue[] vs = db.SortedSetRangeByRank("sort", 1, 2, Order.Ascending);
            for (int i = 0; i < vs.Length; i++)
            {
                var value = db.SortedSetScore("sort", vs[i]);
            } 

 

 

Hash(哈希表)

Hash是一個string類型的field和value的對應表,它更適合來存儲對象,相比於每個屬性進行一次緩存,利用hash來存儲整個對象會占用更小的內存。但是存儲速度並不會更快

db.HashSet("hash", "name","張三");
            db.HashSet("hash", "age", "20");
            db.HashSet("hash", "address", "中國");

 

 

取值也很容易

db.HashGet("hash", "name"); //取單個
db.HashGetAll("hash"); //取所有
db.HashGet("hash", new RedisValue[] { "name", "age" }); //根據指定的hashkey取值

 

 上面也說了,哈希表一般會把一個對象序列化后緩存。這樣比每個屬性緩存一次效率高

 

 

string 存在二進制文件

上面講了。string的值是字符串的。可以是字符串類型,json類型。當然也可以是二進制類型

序列化二進制的方法是BinaryFormatter 命名空間在System.Runtime.Serialization.Formatters.Binary;

BinaryFormatter是不能序列化匿名類的。因為序列化的類必須要標記為Serializable

   [Serializable]
    class user
    {
        public string name;
        public string age;
    }

 

 當然。你也可以把json字符串序列化成二進制文件在緩存。根據你的需求吧。

現在我們把一個對象序列化成二進制文件后在緩存

user u = new user { name = "你好",age="18"};

            var json = JsonConvert.SerializeObject(post);
            byte[] bytes;

            //序列化成二進制
            using(var stream = new MemoryStream())
            {
                new BinaryFormatter().Serialize(stream, u);
                bytes = stream.ToArray();
            }
            db.StringSet("bf", bytes);

            //讀取二進制文件
            byte[] bf = (byte[])db.StringGet("bf");
           using(var stream = new MemoryStream(bf))
           {
               user obj =(user) new BinaryFormatter().Deserialize(stream);
           }

 

 

 

 Redis 事物

Redis因為有並發的問題,所以要考慮到事物。Redis通過CreateTransaction函數(multi)來創建一個事物,調用其Execute函數(exec)提交事物

var db = RedisManager.Instance.GetDatabase();

            //設置值
            db.StringSet("name", "張三");
            db.StringSet("age", 90);
            string name = db.StringGet("name");
            string age = db.StringGet("age");
            Console.WriteLine("name:" + name);
            Console.WriteLine("age:" + age);

            //創建一個事物
            ITransaction trans = db.CreateTransaction();
            //鎖定RedisKey=name RedisValue=張三的緩存
            trans.AddCondition(Condition.StringEqual("name", name));
            Console.WriteLine("begin trans");
            trans.StringSetAsync("name", "Tom");

            bool isExec = trans.Execute(); //提交事物,name才會修改成功 name = Tom

            Console.WriteLine("事物執行結果:" + isExec);

            string _name = db.StringGet("name");
            string _age = db.StringGet("age");
            Console.WriteLine("name:" + _name);
            Console.WriteLine("age:" + _age);

            Console.WriteLine("end trans");

 

執行結果

 

這里通過trans.AddCondition(Condition.StringEqual("name", name)); 鎖定了name,

必須通過 trans.Execute();提交事物。才能成功

 可以試試,在Execute 提交事物之前,先修改name的值,在執行 trans.Execute()的時候,則會失敗,圖中紅色標記部分

 

執行結果

 

因為在trans.Execute()的時候發現值已經被修改了。則回滾事物,導致事物執行失敗

 

 

StackExchange.Redis中對於連續多次的緩存等請求,我們會多次調用相關的函數來執行Redis命令。然而這種方式有個弊端就是每一次的請求都需要等待返回結果

如果在網絡狀況不好的情況下,可能會造成不好的用戶體驗。 

對於這種問題可以用StackExchange.Redis提供的CreateBatch()解決

   IBatch batch = db.CreateBatch();
            Task t1 = batch.StringSetAsync("name", "tom");
            Task t2 = batch.StringSetAsync("age", 20);
            batch.Execute();
            Task.WaitAll(t1, t2);

 batch會把所需要執行的命令打包成一條請求發到Redis,然后一起等待返回結果。這樣批量操作的速度就大大提升啦!

 

 

 StackExchange.Redis中的發布和訂閱

發布端代碼

var db = RedisManager.Instance.GetDatabase();
            db.PublishAsync("name", "張三");
            db.PublishAsync("age", 18);
            db.PublishAsync("address", "長沙");

 

訂閱端代碼

var redis = RedisManager.Instance.GetSubscriber();
       //channel是通道名稱,message是消息
            redis.SubscribeAsync("name", (channel, message) =>
            {
                Console.WriteLine("我叫:" + message);
            });
            redis.SubscribeAsync("age", (channel, message) =>
            {
                Console.WriteLine("我今年:" + message);
            });
            redis.SubscribeAsync("address", (channel, message) =>
            {
                Console.WriteLine("我來自:" + message);
            });

 

先運行訂閱端,然后在打開發布端。否則收不到信息

 

 

 

參考:

https://www.cnblogs.com/bluesummer/p/7677969.html

http://www.cnblogs.com/PatrickLiu/p/8260228.html

http://blog.csdn.net/WuLex/article/details/52637196

 http://www.cnblogs.com/bluesummer/p/7874788.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM