ABP module-zero +AdminLTE+Bootstrap Table+jQuery權限管理系統第十五節--緩存小結與ABP框架項目中 Redis Cache的實現


返回總目錄:ABP+AdminLTE+Bootstrap Table權限管理系統一期

緩存

為什么要用緩存

為什么要用緩存呢,說緩存之前先說使用緩存的優點。

  • 減少寄宿服務器的往返調用(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 Redis Cache

ABP中使用ICacheManager進行緩存管理

ABP中有兩種cache的實現方式:MemroyCache RedisCache,兩者都繼承至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)首先,我們前往https://github.com/dmajkic/redis/downloads下載安裝包,直接下一步下一步就可以了。
然后打開安裝的地址就可以看到如下的文件:
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)地址:https://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. 命令控制台操作 !大家感興趣可以自己玩一下。
    另外關於實體修改后自動更新緩存的實現遠離可以參考
    http://www.cnblogs.com/loyldg/p/using-redis-in-abp-2.html
    這個文章。

Github項目地址:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS
本文鏈接:http://www.cnblogs.com/anyushengcms/p/8013201.html

ABP+AdminLTE+Bootstrap Table權限管理系統一期
Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS
返回總目錄:ABP+AdminLTE+Bootstrap Table權限管理系統一期


免責聲明!

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



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