成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

【PaPaPa】實(shí)現(xiàn)緩存決策:讓你的緩存變的有智慧

開(kāi)發(fā) 項(xiàng)目管理 前端
本來(lái)這一篇我打算放到后面再說(shuō),可是之前泄漏了一點(diǎn)關(guān)于緩存決策的代碼后被好多人催更了。在此感謝大家的支持,讓我更有動(dòng)力的寫(xiě)這個(gè)系列。你們的關(guān)注讓我覺(jué)得我的決定是對(duì)的,我會(huì)堅(jiān)持下去把這個(gè)項(xiàng)目做完。

我有話說(shuō)

本來(lái)這一篇我打算放到后面再說(shuō),可是之前泄漏了一點(diǎn)關(guān)于緩存決策的代碼后被好多人催更了。

在此感謝大家的支持,讓我更有動(dòng)力的寫(xiě)這個(gè)系列。你們的關(guān)注讓我覺(jué)得我的決定是對(duì)的,我會(huì)堅(jiān)持下去把這個(gè)項(xiàng)目做完。

另外非常感謝老虎,在百忙之中給我們趕出需求文檔,當(dāng)我們?cè)谙硎苤苣┑臅r(shí)候他還在公司加班,即便這樣,他依然為我們的開(kāi)源項(xiàng)目奉獻(xiàn)著。

此時(shí)我不知道該說(shuō)些什么,只能以我的行動(dòng)來(lái)回報(bào)大家,廢話不多說(shuō)了,入正題。

緩存決策

先澄清下,這個(gè)名字是我杜撰的,因?yàn)槲矣X(jué)得在我的項(xiàng)目中它起到了這樣的作用。

緩存:在我做的這個(gè)功能中涉及到內(nèi)存和redis兩部分的緩存。

決策:我從百度找的翻譯,指做出決定或選擇,是一種“在各種替代方案中考慮各項(xiàng)因素作出選擇”的認(rèn)知、思考過(guò)程。

那么緩存決策到底是干什么的?

說(shuō)白了就是選擇使用數(shù)據(jù)庫(kù)還是緩存。

如何適合緩存決策

緩存決策的由來(lái) - 我是懶人

因?yàn)槲覒校晕乙朕k法偷懶。

我希望有一個(gè)類(lèi)庫(kù)可以幫助我來(lái)判斷當(dāng)前的數(shù)據(jù)是到緩存里取,還是數(shù)據(jù)庫(kù)里取。

而為了實(shí)現(xiàn)這樣的一個(gè)功能,我覺(jué)得我應(yīng)該建立一個(gè)規(guī)則,這個(gè)規(guī)則來(lái)幫助我判斷當(dāng)前數(shù)據(jù)在緩存里是不是有一份拷貝。

我對(duì)緩存的判斷規(guī)則有什么要求?

就以目前項(xiàng)目來(lái)說(shuō),我緩存是整表緩存的,所以我需要判斷的是當(dāng)前數(shù)據(jù)是屬于哪個(gè)表。

既然如此,那我判斷的依據(jù)應(yīng)該是這樣: 緩存決策規(guī)則.表名列表.包含(數(shù)據(jù).表名) == true

只要滿足上面的條件,說(shuō)明當(dāng)前數(shù)據(jù)在緩存里是有拷貝的。

如何管理這些判斷規(guī)則?

繼續(xù)上面提到的包含,我們?cè)俜治鲆幌?,包含的判斷依?jù)其實(shí)是逐一比對(duì)相等,所以我想了個(gè)類(lèi)名:EqualsMonitorManager,這里的Monitor是監(jiān)視器的意思,后面的類(lèi)都會(huì)跟這個(gè)詞有關(guān)。

這個(gè)類(lèi)有4個(gè)基本的方法:Add、Remove、Get、IsMonitoring ,看起來(lái)其實(shí)是很像字典的對(duì)吧?其實(shí)內(nèi)部實(shí)現(xiàn)確實(shí)依賴了字典,對(duì)字典做了一些封裝。

為了方面以后擴(kuò)展支持到更多場(chǎng)景而不局限于緩存,我定義的時(shí)候使用到了泛型。

  1. public static partial class EqualsMonitorManager<TKey, TValue>  
  2.         where TValue : IEquatable<TValue>  
  3.     {  
  4.         private static class MonitorCaller<TCallerKey>  
  5.         {  
  6.             public static Action<TCallerKey, TValue> Add;  
  7.  
  8.             public static Action<TCallerKey> Remove;  
  9.  
  10.             public static Func<TCallerKey, Func<TValue, bool>, TValue> Get;  
  11.  
  12.             public static Func<TCallerKey, TValue, bool> IsMonitoring;  
  13.         }  
  14.  
  15.         #region Members  
  16.  
  17.         private static Dictionary<string, List<TValue>> _dicStringMonitor = new Dictionary<string, List<TValue>>();  
  18.  
  19.         #endregion  
  20.  
  21.         static EqualsMonitorManager()  
  22.         {  
  23.             StringMonitorCallerInit();  
  24.         }  
  25.  
  26.         private static void StringMonitorCallerInit()  
  27.         {  
  28.             MonitorCaller<string>.Add = (string key, TValue value) =>  
  29.             {  
  30.                 if (!_dicStringMonitor.ContainsKey(key))  
  31.                 {  
  32.                     _dicStringMonitor.Add(key, new List<TValue>());  
  33.                 }  
  34.  
  35.                 _dicStringMonitor[key].Add(value);  
  36.             };  
  37.  
  38.             MonitorCaller<string>.Remove = (string key) =>  
  39.             {  
  40.                 if (_dicStringMonitor.ContainsKey(key))  
  41.                     _dicStringMonitor.Remove(key);  
  42.             };  
  43.  
  44.             MonitorCaller<string>.Get = (string key, Func<TValue, bool> predicate) =>  
  45.             {  
  46.                 if (_dicStringMonitor.ContainsKey(key))  
  47.                     return _dicStringMonitor[key].FirstOrDefault(predicate);  
  48.                 else 
  49.                     return default(TValue);  
  50.             };  
  51.  
  52.             MonitorCaller<string>.IsMonitoring = (string key, TValue value) =>  
  53.             {  
  54.                 if (!_dicStringMonitor.ContainsKey(key))  
  55.                 {  
  56.                     return false;  
  57.                 }  
  58.  
  59.                 return _dicStringMonitor[key].Exists(x => x.Equals(value));  
  60.             };  
  61.         }  
  62.     } 
  1. public static partial class EqualsMonitorManager<TKey, TValue>  
  2.     {  
  3.         public static void Add(TKey key, TValue value)  
  4.         {  
  5.             if (key == null)  
  6.             {  
  7.                 throw new ArgumentNullException();  
  8.             }  
  9.             MonitorCaller<TKey>.Add(key, value);  
  10.         }  
  11.  
  12.         public static void Remove(TKey key)  
  13.         {  
  14.             if (key == null)  
  15.             {  
  16.                 throw new ArgumentNullException();  
  17.             }  
  18.             MonitorCaller<TKey>.Remove(key);  
  19.         }  
  20.  
  21.         public static TValue Get(TKey key, Func<TValue, bool> predicate)  
  22.         {  
  23.             if (key == null)  
  24.             {  
  25.                 throw new ArgumentNullException();  
  26.             }  
  27.             return MonitorCaller<TKey>.Get(key, predicate);  
  28.         }  
  29.  
  30.         public static bool IsMonitoring(TKey key, TValue value)  
  31.         {  
  32.             if (key == null)  
  33.             {  
  34.                 throw new ArgumentNullException();  
  35.             }  
  36.  
  37.             return MonitorCaller<TKey>.IsMonitoring(key, value);  
  38.         }  
  39.     } 

這里的代碼用到了老趙博客中的一篇關(guān)于“逆泛型”的代碼,這里是未經(jīng)優(yōu)化的,寫(xiě)的倉(cāng)促。

這里我就不多解釋為什么會(huì)這么寫(xiě)這個(gè)類(lèi)了,有興趣可以去翻老趙的博客,寫(xiě)的很詳細(xì),對(duì)于初學(xué)者來(lái)說(shuō)這里有點(diǎn)繞,建議可以去看看。

這里只是創(chuàng)建了一個(gè)最基礎(chǔ)的封裝過(guò)的“字典”,用于管理判斷規(guī)則。

初始化判斷規(guī)則

有了管理規(guī)則的類(lèi),那么我們的項(xiàng)目中首先要做的就是初始化這些規(guī)則,否則沒(méi)有規(guī)則后面的寫(xiě)下去也用不了。

細(xì)心的朋友可能會(huì)發(fā)現(xiàn),EqualsMonitorManager的TValue需要繼承自IEquatable接口,因?yàn)閮?nèi)部判斷相等是用了這個(gè)接口的Equals方法。

那么,我們第一個(gè)緩存決策類(lèi)出現(xiàn)了,它就是RedisCacheMonitor。

  1. public class RedisCacheMonitor : IEquatable<RedisCacheMonitor>  
  2.     {  
  3.         public string Key { get { return MonitorConstant.REDIS_KEY; } }  
  4.  
  5.         public string TableName { get; set; }  
  6.  
  7.         public string[] Fields { get; set; }  
  8.  
  9.         #region IEquatable<RedisCacheMonitor> 成員  
  10.  
  11.         public bool Equals(RedisCacheMonitor other)  
  12.         {  
  13.             if (other == null)  
  14.             {  
  15.                 return false;  
  16.             }  
  17.  
  18.             return this.TableName == other.TableName;  
  19.         }  
  20.  
  21.         #endregion  
  22.     } 

我們可以發(fā)現(xiàn),這個(gè)類(lèi)的自由度很大,唯一的約束就是要實(shí)現(xiàn)IEquatable接口,這樣EqualMonitorManager的可擴(kuò)展性就充分被利用了起來(lái)。
而RedisCacheMonitor就可以任由我們來(lái)發(fā)揮,我們只需要告訴EqualMonitorManager如何去判斷相等即可。

TableName表示緩存的表名,F(xiàn)ields是使用了Redis HGet命令的一個(gè)參數(shù)名,表示哪些字段可以作為關(guān)鍵字來(lái)查詢數(shù)據(jù)或者說(shuō)需要緩存哪些字段為關(guān)鍵字。

接下來(lái)就是如何把一個(gè)RedisCacheMonitor加入到EqualMonitorManager

  1. var monitor = new RedisCacheMonitor() { TableName = "User", Fields = new string[] { "Id""UserName" } };  
  2. EqualsMonitorManager<string, RedisCacheMonitor>.Add(monitor.Key, monitor); 

是的,就這么簡(jiǎn)單,我們的緩存規(guī)則就加完了。剩下就是操作Redis,把User表緩存起來(lái)我就不多說(shuō)了。

#p#

自動(dòng)緩存決策與手動(dòng)緩存決策

為什么會(huì)有自動(dòng)和手動(dòng)兩種?

因?yàn)槲也僮鲾?shù)據(jù)庫(kù)用的EF,查詢條件是表達(dá)式樹(shù),為了降低解析表達(dá)式樹(shù)的工作量暫時(shí)選擇了自動(dòng)和手動(dòng)。

如何實(shí)現(xiàn)手動(dòng)緩存決策?

  1. var monitor = EqualsMonitorManager<string, RedisCacheMonitor>.Get(MonitorConstant.REDIS_KEY, x => x.TableName == tableName);  
  2.  
  3. if (monitor != null)  
  4. {  
  5.     //todo something  
  6. }  

手動(dòng)決策很簡(jiǎn)單,只要嘗試獲取一下即可,獲取到monitor就說(shuō)明被緩存了,下面就可以直接取緩存了。

如何實(shí)現(xiàn)自動(dòng)緩存決策?

看到第一篇的應(yīng)該對(duì)下面的代碼有印象,我把之前寫(xiě)的內(nèi)容直接copy過(guò)來(lái)一份:

SaveChangesAsync是EF的異步保存方法,我們要做的事情其實(shí)很簡(jiǎn)單,就是攔截保存方法,代碼中是SaveAsync,這個(gè)是我們自己針對(duì)EF封裝后的方法。

大概思路是這樣的:

想要讓 SaveAsync 聽(tīng)我們的話, override 就派上了用場(chǎng),重寫(xiě) SaveAsync。

調(diào)用基類(lèi)的 SaveAsync 后,再加上保存到Redis的代碼。

這樣一個(gè)SaveAsync就變成了做2件事,先保存到數(shù)據(jù)庫(kù)再保存到Redis,從而杜絕了代碼中到處寫(xiě)保存到Redis的重復(fù)代碼。

  1. public class DataWrapper<T> : EFWrapperBase<T>  
  2.         where T : class,new()  
  3.     {  
  4.         public DataWrapper()  
  5.         {  
  6.             base.Context.EventRegistModel += ModelRegister.Regist;  
  7.         }  
  8.  
  9.         public override async Task<int> SaveAsync()  
  10.         {  
  11.             var result = await base.SaveAsync();  
  12.  
  13.             SaveToRedis();  
  14.  
  15.             return result;  
  16.         }  
  17.  
  18.         private void SaveToRedis()  
  19.         {  
  20.             try 
  21.             {  
  22.                 var type = typeof(T);  
  23.                 var monitor = EqualsMonitorManager<string, RedisCacheMonitor>.Get(MonitorConstant.REDIS_KEY, x => x.TableName == type.Name);  
  24.                 if (monitor != null)  
  25.                 {  
  26.                     foreach (var entity in base.DbSet.Local)  
  27.                     {  
  28.                         foreach (var field in monitor.Fields)  
  29.                         {  
  30.                             var pi = type.GetProperty(field);  
  31.                             RedisSingleton.GetInstance.Client.HSet(type.Name, string.Format("{0}:{1}", pi.Name, pi.GetValue(entity, null).ToString()), entity);  
  32.                         }  
  33.                     }  
  34.                 }  
  35.             }  
  36.             catch (Exception ex)  
  37.             {  
  38.                 Logger.Error(ex.ToString());  
  39.             }  
  40.         }  
  41.  
  42.     } 

源碼

源碼地址:http://git.oschina.net/doddgu/PaPaPa

PS:其實(shí)想想真的不難,主要是一種思路,用到的都是基本的C#語(yǔ)法,關(guān)鍵在于你敢不敢想,而我敢想了,你還在猶豫嗎?后面我們會(huì)有更多敢想敢做的事,歡迎你的加入。

原文出自:http://www.cnblogs.com/doddgu/p/papapa_huancunjuece.html

責(zé)任編輯:林師授 來(lái)源: 尋找和諧的博客
相關(guān)推薦

2022-10-08 00:04:00

緩存架構(gòu)限流

2024-11-01 16:18:52

2021-12-25 22:28:27

緩存穿透緩存擊穿緩存雪崩

2019-07-02 15:21:39

緩存NET單線程

2023-05-04 16:10:13

緩存前端

2023-05-08 09:56:42

GPT技巧邏輯

2024-03-12 10:44:42

2013-08-02 14:19:50

Java日志緩存

2022-08-28 16:31:11

緩存雪崩

2022-07-11 07:36:36

緩存緩存雪崩緩存擊穿

2019-12-11 10:07:02

緩存架構(gòu)數(shù)據(jù)庫(kù)

2009-04-07 10:52:00

職場(chǎng)工作方法

2021-09-13 07:00:01

C# .NET 緩存

2023-04-14 07:34:19

2017-01-19 15:11:37

AndroidRetrofitRxCache

2010-03-24 18:47:43

Nginx緩存

2023-05-15 10:03:00

Redis緩存穿透

2021-06-02 06:49:18

Redis緩存設(shè)計(jì).

2024-12-05 08:31:10

2023-09-05 07:47:14

.NET 7.0內(nèi)存緩存
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 夏同学福利网 | 激情婷婷成人 | 中文字幕在线播放第一页 | 国产成人精品综合 | 日本在线免费视频 | 国产精品久久久久久久久久三级 | 国产精品一区三区 | 97伦理影院 | 成人在线视频免费观看 | 丁香五月网久久综合 | 黄色网址在线免费观看 | 四虎在线观看 | 久久久久久国产精品 | 综合久久久 | 日本精品一区二区三区视频 | 成人伊人 | 一区二区手机在线 | 亚洲精品天堂 | 韩国欧洲一级毛片 | 一级片网址 | 在线精品国产 | 91影片 | 欧美日韩精品中文字幕 | 欧美视频1| 国产一区二区电影 | 国产线视频精品免费观看视频 | 人人精品 | 欧美一a| 国产精品无码久久久久 | 日韩av一区二区在线观看 | 91精品国产91久久久久久最新 | 一区二区视频 | 99久久精品一区二区成人 | 国产99久久精品一区二区永久免费 | av一区二区三区 | 成人在线视频一区二区三区 | 欧美一级小视频 | 国产一级一片免费播放 | 欧美一区二区三区视频在线观看 | 黄色网址大全在线观看 | 亚洲自拍偷拍免费视频 |