最近作一個很是簡單的功能,就是使用ajax請求的方式從服務端請求一段下拉表的數據。html
之前也有作過這個功能,只不過此次作這個功能的時候冒出了一個想法:web
我請求的這段數據它是一段相對比較固定的數據,也就是說它不怎麼改變,也許幾個月纔會改變一次。因爲這種數據的變化週期很長,因此之前作這種功能的時候,會使用緩存進行優化,能夠直接從緩存中讀取數據,避免每一次接收了ajax請求後都要向數據庫要數據,減小服務器與數據庫之間的交互,減輕數據庫服務器的壓力。可是問題來了,數據的變化週期再長終究是要變化的,當數據庫中的數據變化的時候你就要對舊有的緩存內容進行移除(remove)操做,好的,之前我是這樣作的:ajax
public ActionResult GetAllFJs() { //嘗試從緩存中取出數據 var FJIdNames = HttpContext.Cache["FJIdNames"]; if (null == FJIdNames) //緩存中沒有數據 { //從數據庫中查詢出數據 FJIdNames = FJService.GetAll().Select(fj => new { Id = fj.Id, Name = fj.Name }).ToArray(); //將數據緩存起來下一次用(設置一個緩存有效時間,使用絕對過時,到達指定過時時間,緩存失效) HttpContext.Cache.Insert( "FJIdNames", //緩存項的鍵(string) FJIdNames, //緩存項的值(object) null, DateTime.UtcNow.AddMinutes(30), //絕對到期時間(DateTime) System.Web.Caching.Cache.NoSlidingExpiration //滑動到期間隔時間(TimeSpan) ); } //將獲得的數據轉化成json格式字符串 string jsonResult = CommonHelper.ConvertToJsonStr(FJIdNames); //返回給瀏覽器的結果字符串 return Content(jsonResult); }
說明:這是一個 asp.net MVC 中處理一個請求的action方法,其中有一個重要的方法sql
public void Insert(數據庫
string key, --> 緩存項的鍵json
object value, --> 緩存項的值
數組
CacheDependency dependencies, --> 緩存依賴項(這裏不用,後面會用,是重頭戲)瀏覽器
DateTime absoluteExpiration, --> 絕對過時時間點緩存
TimeSpan slidingExpiration --> 滑動過時時間間隔服務器
);
在這裏是利用了緩存的過時時間來對緩存數據進行更新操做,每當緩存數據通過了30分鐘後就要從新從數據庫中拿一次數據來更新緩存中的內容,來看一下執行的結果 (爲了便於展現結果,將絕對過時時間調爲30s):
第一次請求:
(數據庫表中此刻的數據):
(執行結果):
第一次請求的話確定緩存中是沒有數據的,因此要向數據庫要數據;
第二次請求:
(請求以前改變一下數據庫中相應表的數據)
(執行結果):
第二次請求,因爲沒有到緩存項的絕對過時時間,緩存中還有數據,不用向數據庫要數據,從緩存中取出來就行;
過30s後再請求:
(數據庫表中此刻的數據):
(執行結果):
緩存中數據已通過期被移除,須要從新向數據庫請求;
從以上三次請求能夠看到,最後的確是實現了緩存數據的更新。
但一樣能夠看到這樣作有一個壞處:在還沒到達過時時間的這段時間裏,請求的數據依然是原來的緩存中數據,和數據庫中的數據並不一致。
其中設置的絕對過時時間點要根據實際的數據刷新的可容忍度來進行設定,而剛好在個人這個應用場景中的可容忍度最不能把握,它要求的是 當數據庫中的數據改變之後,緩存中對應的數據在下一次請求結束後必定要立刻跟着改變,固然你也能夠把過時時間儘量的調小,調到一秒。固然,這樣的話仍是要頻繁的向數據庫進行請求,那不是背離了咱們本來使用緩存優化的目的了嗎?
因此如今的問題是:有沒有一種方法能讓數據庫和服務器程序創建一種聯繫,這種聯繫比如是一種「心靈感應」,當數據庫表中的數據發生變化的時候,立刻就能讓服務器中的對應的緩存項「感應」到這個變化,從而讓原來的緩存項失效呢?答案固然是,有的。
ASP.NET 有 3 種類型的依賴:
本文要講的是數據庫依賴:數據庫緩存依賴是一項當數據庫中的相關數據被修改時自動使緩存的數據對象失效的技術。
之前不知道有 數據庫依賴 的時候,有想過使用文件或文件夾依賴來實現相似於數據庫依賴緩存的功能,大概的思路就是:用某個文件做爲媒介,在進行了對數據庫表的數據改動後,同時改動一下該文件來觸發緩存的失效。還好我在看了大神們寫的博文之後,立刻中止了我「愚蠢」的想法,那樣作實際上是多此一舉,並且並不能很好的實現,有現成的數據庫依賴不用幹嗎。
一、配置:
1)在當前網站mvc項目下的Web.config文件中加入
<!--(數據庫鏈接字符串)<configuration> 結點下配置-->
<connectionStrings> <add name="connStr" connectionString="server=127.0.0.1; user id=sa; password=root; database=LZXF" providerName="System.Data.SqlClient" /> </connectionStrings>
<!--(緩存數據庫依賴配置)<system.web> 結點下配置--> <caching> <sqlCacheDependency enabled="true"> <databases> <add name="LZXF" pollTime="5000" connectionStringName="connStr" /> </databases> </sqlCacheDependency> </caching>
2)在 Application_Start() 中加入
//配緩存數據庫依賴 string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["connStr"].ToString(); //啓動數據庫的數據緩存依賴功能 SqlCacheDependencyAdmin.EnableNotifications(connectionString); //啓用數據表緩存 SqlCacheDependencyAdmin.EnableTableForNotifications(connectionString, "(表名)"); //第二個參數能夠是單個表名或表名的數組
二、代碼部分
public ActionResult GetAllFJs() { //嘗試從緩存中取出數據 var FJIdNames = HttpContext.Cache["FJIdNames"]; if (null == FJIdNames) //緩存中沒有數據 { //從數據庫中查詢出數據 FJIdNames = FJService.GetAll().Select(fj => new { Id = fj.Id, Name = fj.Name }).ToArray(); //將數據緩存起來下一次用(使用數據庫依賴的緩存,當數據庫中對應的表的數據發生改變時,緩存失效) HttpContext.Cache.Insert("FJIdNames", FJIdNames, new SqlCacheDependency("LZXF", "T_FJs")); } //將獲得的數據轉化成json格式字符串 string jsonResult = CommonHelper.ConvertToJsonStr(FJIdNames); //返回給瀏覽器的結果字符串 return Content(jsonResult); }
其中的 SqlCacheDependency(數據庫緩存依賴類) 是最重要的一個類,就是它創建起了數據庫和服務器程序之間 「溝通的橋樑」 ,
使用它的一個構造方法:
public SqlCacheDependency(string databaseEntryName, string tableName) 來建立一個數據庫緩存依賴類對象,傳給建立緩存項的方法Insert, 這樣來創建該緩存項的數據庫依賴,每當該指定表中發生數據的變更時都會銷燬該緩存項。
看一下執行結果:
沒改變數據庫表數據以前:
(執行結果):
改變數據庫表數據以後:
(執行結果):
改變了數據庫表的數據之後再去請求數據,請求到最新的數據,說明舊的緩存被移除了
用完了之後就會很疑惑,它是怎麼實現的呢?
思考:首先是改動了數據庫表中的數據,這一步操做之後一定要引起某種操做。在數據庫中改變表中數據會觸發操做?講的不就是觸發器嗎。
來看一下數據庫中多了些什麼:
打開sqlServerManagement查看數據庫發現
多了一個 AspNet_SqlCacheTablesForChangeNotification 表,表中內容:
要找的觸發器在這裏:
看一下觸發器裏面的內容:
說的就是:當 T_FJs 表中發生了 INSERT, UPDATE, DELETE 這些操做,就去執行 dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure 這個存儲過程,這個存儲過程是咱們開啓sql server的緩存依賴自動生成的
找一下存儲過程 dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure,在這裏:
內容是:
因此最後對原理的總結,我就引用一篇大神博客(https://www.lanhusoft.com/Article/290.html)裏的總結:
當sql server啓用緩存依賴以後,就會在對應的數據庫添加相應的表、觸發器和一些存儲過程。它是利用觸發器來監測表的數據的變化,若是有增、刪、改就插入數據到通知表,而後通知訂閱這個通知的網站此緩存項失效。
最後要說的是使用緩存依賴也有限制:必須用ASP.Net和SQL Server開發應用,也就是SqlCacheDependency是基於微軟的那套體制。
參考博文地址:
https://www.cnblogs.com/SkySoot/archive/2012/08/15/2640559.html
https://www.lanhusoft.com/Article/290.html
這是個人第一篇博文,之前想過爲何要寫博文這個問題?如今網上隨便一搜都有本身想要的內容,並且有些大神寫的很不錯。後來慢慢的發現每一次遇到問題都要上網搜博客看,並且不少時候遇到的是同一個問題,可能之前就已經思考過了,如今又要浪費時間去從頭找着看已經看過的東西,那我爲何不本身寫好了整理好了存着呢。固然,方便本身的同時,但願也能方便到正在閱讀本文的你。謝謝!