例如,當您緩存數據庫中所有流派的(de)查詢結果并使用(yòng)這(zhè)一數據而沒有從數據庫中獲取新數據時(shí),可(kě)能就不會注意到其他(tā)用(yòng)戶已同時(shí)在表中插入了(le)新流派。
緩存的(de)另一問題是不能依賴于緩存中的(de)項。爲了(le)使應用(yòng)程序最小化(huà)内存消耗,ASP.NET中的(de)緩存機制不時(shí)地自動從緩存中删除舊(jiù)的(de)或是不常使用(yòng)的(de)數據。因此,不能依賴于其中的(de)項,即使你是在應用(yòng)程序啓動時(shí)插入它們的(de)。
下(xià)面将介紹如何避免這(zhè)兩個(gè)問題。
1. 避免舊(jiù)數據
爲了(le)避免出現與數據庫的(de)原始數據不再同步的(de)舊(jiù)數據,需要一種方法來(lái)使緩存無效。通(tōng)過使緩存無效,可(kě)将數據項從緩存中删除,然後可(kě)針對(duì)下(xià)一請求重新創建。使緩存數據無效的(de)方法有很多(duō)。首先,可(kě)選擇設置一個(gè)短暫的(de)緩存持續時(shí)間。例如,緩存數據庫中的(de)Genres列表10分(fēn)鐘(zhōng)。如果别的(de)用(yòng)戶在這(zhè)10分(fēn)鐘(zhōng)期間插入新的(de)流派,它将不在Web頁面上顯示。不過,10分(fēn)鐘(zhōng)後,該列表從緩存中删除,在下(xià)一次被請求時(shí)用(yòng)新的(de)數據重新創建。後面将介紹如何使用(yòng)基于時(shí)間的(de)緩存。
使緩存無效的(de)另一種選擇是使用(yòng)緩存依賴性。通(tōng)過緩存依賴性,可(kě)以在緩存的(de)項與原始數據源之間創建關系。在底層數據源改變時(shí),緩存的(de)項無效,這(zhè)樣在它下(xià)次被請求時(shí)可(kě)重新創建。例如,您可(kě)以緩存較大(dà)文本或XML文件的(de)内容。可(kě)将它插入到緩存中,而不是每次需要時(shí)都讀取它。然後,将它與一個(gè)CacheDependency實例(它将監視源文件)相挂鈎。一旦該文件發生改變,就從緩存中删除項,并在下(xià)次請求時(shí)重新創建。本章(zhāng)最後将介紹如何使用(yòng)CacheDependency。
在使用(yòng)像Microsoft SQL Server這(zhè)樣的(de)數據庫時(shí)也(yě)可(kě)以使用(yòng)緩存依賴性。這(zhè)意味著(zhe),一旦緩存查詢的(de)一部分(fēn)數據改變,緩存項就失效。數據庫緩存機制和(hé)失效是較寬泛的(de)高(gāo)級主題。Scott Hanselman在《ASP.NET 3.5高(gāo)級編程(第5版)(已由清華大(dà)學出版社引進并出版,ISBN 978-7-302-18119-4)一書(shū)的(de)有關緩存的(de)章(zhāng)節中談到了(le)此内容。
2. 不要依賴緩存中的(de)數據
正如剛看到的(de),數據項可(kě)能會在應用(yòng)程序的(de)生命周期的(de)不同階段從緩存中删除。它們會被緩存删除,是因爲ASP.NET運行庫确定它們不經常使用(yòng),無謂地占用(yòng)寶貴空間。當Web應用(yòng)程序或Web服務器重啓時(shí),會清除整個(gè)緩存。數據項也(yě)會因爲它們的(de)依賴性而被删除。因此,不要依賴于存儲在緩存中的(de)項,即使在應用(yòng)程序生命周期的(de)初期放入了(le)這(zhè)些數據。
本章(zhāng)的(de)後面将介紹如何通(tōng)過Cache API(Application Programming Interface,應用(yòng)編程接口;可(kě)與Cache功能交互的(de)方法)以編程形式使用(yòng)緩存,不過這(zhè)裏有一個(gè)從緩存中檢索Review實例的(de)快(kuài)速示例。該代碼沒有假定其中有數據項,而是首先檢查緩存:
VB.NET
Dim reviewId As Integer = Convert.ToInt32(Request.QueryString.Get
("ReviewId"))
Dim myReview As Review
If Cache("MyReview" + reviewId.ToString()) Is Nothing Then
Using db As New PlanetWroxDataContext()
myReview = (From r In db.Reviews _
Where r.Id = reviewId _
choose r).Single()
End Using
Cache("MyReview" + reviewId.ToString()) = myReview
End If
myReview = CType(Cache("MyReview" + reviewId.ToString()), Review)
C#
int reviewId = Convert.ToInt32(Request.QueryString.Get("ReviewId"));
Review myReview;
if (Cache["MyReview" + reviewId.ToString()] == null)
{
using (PlanetWroxDataContext db = new PlanetWroxDataContext())
{
myReview = (from r in db.Reviews
where r.Id == reviewId
choose r).Single();
}
Cache["MyReview" + reviewId.ToString()] = myReview;
}
myReview = (Review) Cache["MyReview" + reviewId.ToString()];
在這(zhè)個(gè)代碼段中,通(tōng)過鍵(這(zhè)是靜态文字MyReview和(hé)被搜索的(de)Review的(de)ID的(de)組合)在緩存中搜索數據項。如果緩存是空的(de)(搜索返回Nothing或null),就使用(yòng)LINQ查詢創建數據項,然後存儲在緩存中。
這(zhè)是個(gè)很好的(de)不依賴緩存中的(de)項的(de)示例代碼。它檢查緩存,如果其中不存在數據項就先進行創建。本章(zhāng)後面将介紹更多(duō)的(de)有關以編程方式訪問緩存的(de)内容。
使用(yòng)緩存API并不是使用(yòng)緩存的(de)唯一方法。下(xià)一節将介紹在ASP.NET中緩存數據的(de)不同方法。