[翻譯]ASP.NET MVC 3 開發的20個秘訣(二十)[20 Recipes for Programming MVC 3]:緩存結果數據加速頁面載入


議題

隨着網站的發展,大量用戶訪問流行內容和動態內容,這兩個方面的因素會增加平均的載入時間,給Web服務器和數據庫服務器造成大量的請求壓力。而大量的數據請求就需要強大的數據庫處理能力來支撐。改進更加只能的程序,以極少不必要的數據庫訪問或動態處理請求,可以節省添加更多服務器的費用以及顯著提高Web應用程序的整體速度。

 

解決方案

實現OutputCacheAttribute類,緩存不經常改變的數據或者相對固定的動作。

 

討論

MVC3中實現緩存是非常容易的事情。將下面的屬性添加在某個控制器的動作上即可完成:

 

[OutputCache (Duration=600)]

 

這個語句將自動緩存該視圖600秒(或10分鍾)共享給每個訪問此頁的用戶。這就意味着針對代碼進行簡單的修改當你有1000名用戶同時訪問此頁,只需要通過一次數據加載,可節約數以千計的數據庫請求以及IIS處理負載。

 

輸出緩存的屬性看起來非常簡單,但是當你打開引擎蓋的時候,也可能會發現這輛車的引擎原來如此復雜。當然除非你原本就是名機械師。這個屬性提供了很多關於緩存的方式,必須持續緩存時間,甚至還添加了SQL依賴,在這個秘訣中我們會深入探討一番。

 

按照時間緩存非常簡單,你只需要告訴MVC視圖應該被緩存多少秒即可。至於緩存存儲的位置,是客戶端瀏覽器還是服務器或者是它們的組合,這個問題稍微有點復雜。一個好的做法是首先分析被緩存的內容數據,如果是緩存多個用戶共享的數據,緩存到服務器上更為合適;然而如果是個人數據,比如個人定制的網頁,還是將其緩存在用戶的瀏覽器中更好。雖然緩存可以說是個偉大的發明,但是它也是有局限性的。通常情況下,緩存的最大限制是內存,不是一切都可以緩存在服務器上。

 

然而,最有趣的方式還是SQL依賴。OutputCache允許數據一直被緩存,直到它在數據中的內容發生了實際的變化,這是一個非常有用的功能。就拿圖書來舉例,新書並不是經常增加的,因此可以為圖書設置一個緩存時間(例如24小時)。但是,如果在緩存過期之前添加了一本新書,又或者是在漫長的一周或幾天里根本就沒有添加新書?第一種情況,添加一本新書不能及時出現,用戶是會不高興的。而第二種情況,因為沒有新書被添加,每天都要發起不必要的服務器請求。使用SQL依賴的方式,像我們希望的那樣,當圖書的表發生變化時緩存能被立即更新。

 

這是一個非常棒的功能,在其他編程語言中,你需要手動控制緩存,你需要自己手動更新無效緩存。相信我,這很容易就會讓你錯過一兩個應該正常清除的緩存。

 

在接下來的示例中,將緩存圖書列表頁面。默認情況下,如果沒有設置VaryByParam的值,MVC3將會自動創建一個唯一的緩存對象。這是個相當棒的功能,按二在這本書上面的例子里,搜索關鍵字也會作為輸入參數之一,但是可能輸入數以百計不同的關鍵字組合,所以這個變量不應該被緩存(這就是上面提高的會產生內存警告的問題)。下面修改后啟用緩存的BooksController控制器:

 

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using System.Web.Mvc;
using MvcApplication4.Models;
using MvcApplication4.Utils;
using PagedList;
namespace MvcApplication4.Controllers
{
public class BooksController : Controller
{
private BookDBContext db = new BookDBContext();
//
// GET: /Books/
[OutputCache(Duration=600, VaryByParam=
"sortOrder;filter;page")]
public ViewResult Index(string sortOrder,
string filter, string Keyword, int page = 1)
{
...
return View(books.ToPagedList(currentPage,
maxRecords));
}
...
}

}

 

這段代碼是非常不錯的緩存方案,可以立即降低服務器負載。接下來,將這個例子擴展為SQL依賴,在開始工作之前必須還要做一些設置工作。首先是修改Web.config,在文件中定義一個數據庫鏈接,然后,將緩存部分的SQL依賴設置如下:

 

<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="ApplicationServices" connectionString=
"data source=.\SQLEXPRESS;Integrated Security=SSPI;
AttachDBFilename=|DataDirectory|aspnetdb.mdf;
User Instance=true"
providerName="System.Data.SqlClient"
/>
<add name="BooksDBContext" connectionString=
"Server=.\SQLEXPRESS;Database=
MvcApplication4.Models.BookDBContext;
Trusted_Connection=true"
providerName=
"System.Data.SqlClient"
/>
</connectionStrings>
...
<system.web>
<caching>
<sqlCacheDependency enabled="true" pollTime="2000">
<databases>
<add name = "MvcApplication4.Models.BookDBContext"
connectionStringName
= "BooksDBContext"/>
</databases>
</sqlCacheDependency>
</caching>
...
</system.web>
...
</configuration>

 

在上面的例子中,將pollTime設置為2000毫秒,也就是說,每2秒中,就會查詢一次緩存數據庫是否被更改,這個變量設置可以根據你的實際需求來修改。

 

現在,需要修改Global.asax.cs文件,必須在Application_Start方法中通過SqlCacheDependencyAdmin類的EnableTableForNotifications方法為每個需要緩存的表添加監聽功能。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using MvcApplication4.Models;
using System.Data.Entity;
using System.Globalization;
using System.Threading;
using MvcApplication4.Utils;

namespace MvcApplication4
{
public class MvcApplication : System.Web.HttpApplication
{
...
protected void Application_Start()
{
Database.SetInitializer<BookDBContext>(
new BookInitializer());

AreaRegistration.RegisterAllAreas();

RegisterGlobalFilters(GlobalFilters.Filters);

RegisterRoutes(RouteTable.Routes);

String connectionString =
System.Configuration.ConfigurationManager.ConnectionStrings
["BooksDBContext"].ConnectionString;

System.Web.Caching.SqlCacheDependencyAdmin.
EnableNotifications(connectionString);

System.Web.Caching.SqlCacheDependencyAdmin.
EnableTableForNotifications(connectionString, "books");
}
...
}

}

在命令行窗口中,執行如下步驟來完成SQL通知的功能配置工作:

 

點擊“開始”按鈕 -> 選擇“運行”

輸入“cmd”並回車

cd %windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_regsql.exe -S .\SQLEXPRESS -ed-dMvcApplication4.Models.BookDBContext -et -t books -E

 

務必要你自己的信息,替換命令中的服務器名、數據庫名以及表名。此外,如果你的數據庫包含用戶名和密碼,將需要包含額外的輸入參數(-U-P)。命令運行后,應該會顯示兩條成功信息,第一條,說明數據庫緩存功能啟用;第二條說明指定表緩存成功。

 

最后,使用SQL依賴緩存需要對BooksController稍作修改。此外,因為更換應用程序緩存方式,之前設置的緩存持續時間需要修改為Int32的最大值。

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using System.Web.Mvc;
using MvcApplication4.Models;
using MvcApplication4.Utils;
using PagedList;

namespace MvcApplication4.Controllers
{
public class BooksController : Controller
{
private BookDBContext db = new BookDBContext();
//
// GET: /Books/
[OutputCache(Duration=Int32.MaxValue, SqlDependency =
"MvcApplication4.Models.BookDBContext:books",
VaryByParam="sortOrder,filter,page")]
public ViewResult Index(string sortOrder, string filter,
string Keyword, int page = 1)
{
...
return View(books.ToPagedList(currentPage,
maxRecords));
}
...
}
}

 

在以前的MVC版本中,是不支持局部緩存的,這就意味着每次都需要將整個動作的結果進行緩存。目前在MVC3版本中開始支持局部緩存。實現這個功能,需要創建一個類似於秘訣1.14中使用Ajax提交表單的自動作。在BookCommentsController的這兩個活動都至返回分部視圖,而都無需緩存父級動作中的緩存內容。這是一個非常棒的改進,可以將你的代碼與那些不經常改變的緩存內容進行有效的隔離。

 

參考

OutputCacheAttribute SqlCacheDependencyAdmin 原書地址 書籍源代碼


免責聲明!

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



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