ABP module-zero +AdminLTE+Bootstrap Table+jQuery許可權管理系統第十五節--快取小結與ABP框架專案中 Redis

安與生發表於2017-12-14

ABP+AdminLTE+Bootstrap Table許可權管理系統一期 Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS

為什麼要用快取

為什麼要用快取呢,說快取之前先說使用快取的優點。

  • 減少寄宿伺服器的往返呼叫(round-trips)。
  • 如果快取在客戶端或是代理,將減少對伺服器的請求,減少頻寬。
  • 減少對資料庫伺服器的往返呼叫(round-trips)。
  • 當內容快取在web伺服器,能夠減輕對資料庫的請求。
  • 減少網路頻寬。
  • 避免了重新生成可重用內容的時耗。
  • 提高效能
  • 因為快取減少了round-trips, network traffic(網路頻寬),並避免- 了生成可重用內容的時耗,所以對效能有巨大的提高。

傳統的快取方式

傳統的快取方式如下面這張圖

image.png
之前我們處理方式處理起來也很簡單

  1. 頁面輸出快取,直接在 ASP.NET中頁面快取的使用OutputCache 在aspx頁的頂部加這樣一句即可: <%@ OutputCache Duration="60" VaryByParam="none" %> Duration 表示快取的時間秒,必選,否則報錯。
  2. 第二種方式 if (this.Cache["Keys"] == null) { this.Cache.Insert("Keys", List, null, DateTime.Now.AddHours(2), TimeSpan.Zero); }

這裡是檢查快取中Keys是否存在,如果不存在,則寫入一個新的值List.還有其他的一些使用方法。

image.png

上面兩種方式顯然不在現在使用範疇,也不在我想說的範疇之內。,年代貌似有點久遠,不用webform基本用不到。現在我們更多是的使用MVC。 我們想說的是MVC輸出快取。

MVC快取

輸出快取Outputcache ,分為Action輸出快取和Controller輸出快取。使用的場景包括某個頁面的資料更新不是很頻繁,不需要每次都從資料庫區查詢。快取起來從記憶體中讀取。

資料快取:是相對於全域性的。任何地方需要呼叫的時候都可以去呼叫。使用的場景包括許可權管理這種模組的。每個角色對於選單的訪問都是固定的,所以有必要將角色,許可權,選單這種資料做一個全域性的資料快取。修改時再做快取的更新。

輸出快取和資料快取區別:打個比方輸出快取就像是“區域性變數”,資料快取就像是全域性變數(只是個比喻)。

Controller輸出快取和 Action快取使用方式是一樣的,就是Controller 或Action上打[OutPutCache]特性標籤。但是他們之間又是有區別的。

一、控制器快取

Control快取的作用域是整個控制器,所以在這個控制器下的所有Action都會被快取起來。Control快取的粒度比較粗,應用也比較少些。 [OutputCache(Duration = 10)] public class HomeController : Controller { public ActionResult Index() { ViewBag.CurrentTime = DateTime.Now; return View(); } } 二、Action快取 將[OutPutCache]特性標籤打在Action上,這樣,只有加快取的Action才會有快取,其他的Action是沒有的。

Outputcache特性常用的屬性引數

名稱 描述
AllowMultiple 獲取或設定一個值,該值指示是否可指定篩選器特性的多個例項。
CacheProfile 獲取或設定快取配置檔名稱。
ChildActionCache 獲取或設定子操作快取。
Duration 獲取或設定快取持續時間(以秒為單位)。
Location 獲取或設定位置。
NoStore 獲取或設定一個值,該值指示是否儲存快取。
Order 獲取或者設定執行操作篩選器的順序。
SqlDependency 獲取或設定 SQL 依賴項。
TypeId (從Attribute繼承。)
VaryByContentEncoding 獲取或設定基於內容變化的編碼。
VaryByCustom 獲取或設定基於自定義項變化的值。
VaryByHeader 獲取或設定基於標頭變化的值。
VaryByParam 獲取或設定基於引數變化的值。

輸出快取CacheProfile使用配置檔案設定快取

舉例其中的CacheProfile,這種方式便於統一配置,當然也可以設定引數duration、location 、varybyparam等。我們需要在system.web 節點下加入這些

`






其實作用和效果還是一樣,無非就是方便點,統一的配置引數都直接寫webconfig檔案裡面。其實也可以Controller中寫。 配置好了之後我們直接在控制器呼叫相應的名字的OutputCache特性標籤即可。 [OutputCache(CacheProfile= "TestConfigCache")] public ActionResult Index() { ViewBag.CurrentTime = DateTime.Now; return View(); } ` 更多的方式,需要下去再研究下。

ABP中使用ICacheManager進行快取管理

ABP中有兩種cache的實現方式:MemroyCacheRedisCache,兩者都繼承至ICache介面(準確說是CacheBase抽象類)。ABP核心模組封裝了MemroyCache來實現ABP中的預設快取功能。 Abp.RedisCache這個模組封裝RedisCache來實現快取(通過StackExchange.Redis這個類庫訪問redis)。

ABP給出了一個抽象快取基類。並在內部使用了該抽象基類。使用 MemoryCache 來實現了該抽象基類。它能夠被任何其它的快取類來擴充套件。Abp.RedisCache 包就擴充套件了該快取基類。 ABP對外提供了一個快取介面ICacheMananger。我們通過建構函式注入這個介面來獲取快取。示例如下:

image.png

在這個示例中,我們注入了 ICacheManager介面,s並且獲取了一個名稱為ControllerCache的快取。首先我們先對ControllerCache進行清除,然後存入快取,快取的名字是大小寫敏感的,那就是"ControllerCache"和"CONTROLLERCACHE"取得的快取內容是不同的。

注意:GetCache方法 千萬不要在你的建構函式中使用GetCache方法。如果類不是一個單例物件那麼該快取可能會被dispose掉。

ICache

ICacheManager.GetCache方法返回了一個ICache物件。每一個快取都是基於名稱單例存在的。只有首次訪問時才會被建立,以後你每次用相同的名稱去獲取的快取都是相同的。所以我們可以在不同的類中使用相同的名稱來共享相同的快取。

在示例程式碼中,我們簡單的使用了ICache.Get方法,它有兩個引數:

  • key : 要獲取的快取項的唯一識別符號
  • factory:如果根據給定的key獲取到的快取項為空,那麼factory將會建立一個識別符號為key的快取,並且返回該快取

ICache介面還有其它方法,如前面Clear(),Get(),GetOrDefaultSetRemoveClear。當然也有這些方法的非同步(async)版本。如下圖,我就懶得寫了。

image.png

ITypedCache

ICache 介面用key(字串型別)來獲取快取value(object型別)。ITypedCacheICahe提供了一個 型別安全 的包裝;為了使型別安全轉換(ICacheITypedCache),我們可以用擴充套件方法 AsTyped,而不需要寫其它強制型別轉換的程式碼,如下所示: ITypedCache<int, Item> myCache = _cacheManager.GetCache("MyCache").AsTyped<int, Item>();

Configuration

快取的過期時間預設是60分鐘。它是變化的。如果你在60分鐘內沒有使用該快取,該快取會被自動的移除。如果你想改變所有的快取或者指定的快取來的預設過期時間,你可以這樣做,實現如下: //對所有快取的配置 Configuration.Caching.ConfigureAll(cache => { cache.DefaultSlidingExpireTime = TimeSpan.FromHours(2); }); //對指定快取的配置 Configuration.Caching.Configure("MyCache", cache => { cache.DefaultSlidingExpireTime = TimeSpan.FromHours(8); });

這段程式碼你應該放在模組(module)的 PreInitialize 方法中。如上所示:MyCache將會在8小時後過期,而其他的快取將在2小時後過期。

這些配置將會在首次建立快取的時候生效。配置不僅僅侷限於DefaultSlidingExpireTime,你可以利用ICache介面中的屬性獲取方法來自由的配置並且初始化它們。

Entity Caching

ABP的快取系統是以通用為目的,它有一個 EntityCache 基類,如果你需要的話,這個基類可以幫助你快取實體。使用這個基類,我們可以通過ID取得實體,並且我們通過ID來快取實體,這樣以後就不需要頻繁的查詢資料庫去取得實體。假設我們有個Person實體,像下面一樣: public class Person : Entity { public string Name { get; set; } public int Age { get; set; } }

並且,假設我們通過該實體的Id,需要頻繁呼叫取得Person實體的Name。首先,我們應該建立一個類來儲存 cache items: [AutoMapFrom(typeof(Person))] public class PersonCacheItem { public string Name { get; set; } }

我們 不應該直接儲存實體到快取中 因為快取的時候需要序列化快取物件而實體可能不能被序列化(尤其是實體的導航屬性)。這就是為什麼我們定義了一個簡單的像DTO的類來儲存資料到快取中。我們新增了 AutoMapFrom 特性,這是因為我們想使用 AutoMapper 來自動的轉換 Person 實體為 PersonCacheItem 物件。如果我們不使用 AutoMapper,那麼我們應該重寫 EntityCache 類的 MapToCacheItem 方法手動轉換/對映它。

然而這不是必須的,我們可能想定義一個介面為快取類: public interface IPersonCache : IEntityCache<PersonCacheItem> { } 最後,我們可以建立快取類來快取Person實體: public class PersonCache : EntityCache<Person, PersonCacheItem>, IPersonCache, ITransientDependency { public PersonCache(ICacheManager cacheManager, IRepository<Person> repository) : base(cacheManager, repository) { } }

這樣就OK了,我們的person快取已經準備好可以使用了。快取類可以使瞬時(如同這個例子)或者是單例。這不是說快取資料是瞬態的。在你的應用程式中它一直是全域性快取並且是執行緒安全的。

現在,無論在什麼地方我們需要取得Person的Name,我們可以通過Person的Id從快取中取得它。如下所示: public class MyPersonService : ITransientDependency { private readonly IPersonCache _personCache; public MyPersonService(IPersonCache personCache) { _personCache = personCache; } public string GetPersonNameById(int id) { return _personCache[id].Name; //alternative: _personCache.Get(id).Name; } } 我們很容易的注入 IPersonCache 介面,通過該介面取得快取項和Name屬性。

那麼EntityCache是怎麼工作的?

  • 在首次呼叫的時候我們通過倉儲從資料庫中取得實體。那麼隨後的呼叫都是從快取中取得。
  • 如果實體被更新或者刪除,它會自動的無效實體。因此,它會在下次呼叫的時候重新從資料庫中檢索資料。
  • 使用 IObjectMapper 介面來對映實體到快取項。IObjectMapper 介面在 AutoMapper 中被實現。所以,如果你使用了自動對映,那麼就需要 AutoMapper模組。你可以重寫 MapToCacheItem 方法手動對映它到快取項。
  • 使用快取類的FullName作為快取的Name,你可以通過傳入的快取名到基類的建構函式來改變它。
  • 它是執行緒安全的。 如果你有更復雜的快取需求,那麼你需要擴充套件 EntityCache 類或者建立你自己的解決方案。

Redis Cache 整合

Redis是什麼,Redis是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。它可以用作資料庫、快取和訊息中介軟體。它支援多種型別的資料結構,如字串(strings)、雜湊(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)與範圍查詢、bitmaps、hyperloglogs和地理空間(geospatial)索引半徑查詢。 Redis 是完全開源免費的,遵守BSD協議,是一個高效能的key-value資料庫。 Redis 與其他 key - value 快取產品有以下三個特點

  • Redis支援資料的持久化,可以將記憶體中的資料儲存在磁碟中,重啟的時候可以再次載入進行使用。
  • Redis不僅僅支援簡單的key-value型別的資料,同時還提供list,set,zset,hash等資料結構的儲存。
  • Redis支援資料的備份,即master-slave模式的資料備份。 Redis 優勢
  • 效能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
  • 豐富的資料型別 – Redis支援二進位制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 資料型別操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要麼成功執行要麼失敗完全不執行。單個操作是原子性的。多個操作也支援事務,即原子性,通過MULTI和EXEC指令包起來。
  • 豐富的特性 – Redis還支援 publish/subscribe, 通知, key 過期等等特性。
  • 多實用工具 - Redis是一個多實用工具,可用於多種用例,如:快取,訊息佇列(Redis本地支援釋出/訂閱),應用程式中的任何短期資料,例如,web應用程式中的會話,網頁命中計數等。

(1)首先,我們前往github.com/dmajkic/red…下載安裝包,直接下一步下一步就可以了。 然後開啟安裝的地址就可以看到如下的檔案:

image.png
(2)然後啟動Redis服務,我們cmd到安裝目錄下,然後輸入命令redis-server.exe redis.windows.conf 就會看到下面的畫面證明我們啟動服務成功。
image.png
abp預設Cache Mananger是使用in-memory來快取。所以,這可能會成為一個問題,如果有多個併發的Web服務執行在同一個應用中。在這種情況下,你可能想要一個分散式/中央快取伺服器。那麼,你可以使用Redis來作為你的快取服務。 首先,你需要安裝 Abp.RedisCachenuget package 到你的專案中(你可以安裝它到你的Web專案)。這裡我遇到一個錯誤。
image.png
開始的時候我搞了半天不知道為什麼會出現這個莫名其妙的錯誤,後來才發現,原來我引入Abp.RedisCache版本和abp版本不一致。才導致的這個錯誤,比如你abp是3.1.1,那麼你的Abp.RedisCache最好也是對應的版本,最好的話把abp和Abp.RedisCache都升級到最新版本,就不會有錯誤了。 然後我們看看Abp.Runtime.Caching.Redis;依賴項以及之間的關係。
image.png
然後在ABPCMSWebModule配置一下。
image.png
ABPCMSApplicationModule中引入。
image.png
Web.config中配置
image.png
你也可以新增配置到appSettings來設定Redis資料庫的Id。如: <add key="Abp.Redis.Cache.DatabaseId" value="2"/> 在同一個伺服器上使用不同的資料庫Id是非常有用的這可以建立不同的Key Spaces(隔離快取)。 UseRedis有一個過載方法,你可以通過這個方法來傳入配置引數,這可以覆蓋掉配置檔案中的配置。關於Redis的其他配置可以檢視Redis文件

在下面UserList打下斷點除錯進去。

image.png
看到效果如下圖,證明我們AbpRedisCache引入成功。
image.png
當然為了更好的進行視覺化操作,我建議使用跨平臺開源Redis DB管理工具(Redis Desktop Manager)地址:redisdesktop.com/download 下載下來直接下一步下一步安裝即可。
image.png
然後執行專案,然後我們在看下Redis Desktop Manager工具,效果如下圖:
image.png
使用視覺化工具很方便

  1. 新建連線,輸入redis主機host,埠號port,再起個生動形象,簡明達意的別名。
  2. 該工具支援根據篩選條件查詢key,add new key,reload等。
  3. 支援常用redis操作,針對目標key執行rename,delete,addrow,reload value操作。
  4. 命令控制檯操作 !大家感興趣可以自己玩一下。 另外關於實體修改後自動更新快取的實現遠離可以參考 www.cnblogs.com/loyldg/p/us… 這個文章。

Github專案地址:github.com/Jimmey-Jian…

ABP+AdminLTE+Bootstrap Table許可權管理系統一期 [Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS](https://github.com/Jimmey-Jiang/ABP-

相關文章