ASP.NET狀態管理之四:Cache

來源:互聯網
上載者:User
一、 Cache概述

   
    既然緩衝中的資料其實是來自資料庫的,那麼緩衝中的資料如何和資料庫進行同步呢?一般來說,緩衝中應該存放改動不大或者對資料的即時性沒有太多要求的資料。這樣,我們只需要定期更新緩衝就可以了。相反,如果緩衝的更新頻率過快的話,使用緩衝的意義就不是很大了,因此更新緩衝的時候需要一次性從資料庫中讀取大量的資料,過於頻繁地更新緩衝反而加重了資料庫的負擔。
那麼ASP.NET中的Cache又提供了哪些緩衝的到期策略呢?
· 永不到期。和Application一樣,緩衝永不到期。
· 絕對時間到期。緩衝在某一時間到期,比如5分鐘後。
· 變化時間到期(平滑到期)。緩衝在某一時間內未訪問則逾時到期,這個和Session有點類似,比如我們可以設定緩衝5分鐘沒有人訪問則到期。
· 依賴到期。緩衝依賴於資料庫中的資料或者檔案中的內容。一旦資料庫中某些表的資料發生變動或者檔案內容發生變動,則緩衝自動到期。
緩衝到期後我們就要更新緩衝了,ASP.NET提供了兩種更新策略。
· 被動更新。緩衝到期以後手動進行更新。
· 主動更新。緩衝到期以後在回調方法中更新。

二、 Cache效能與到期策略

首先,在頁面上添加兩個按鈕,並雙擊按鈕實現Click事件處理方法。

 

<asp:Button ID="btn_GetDataFromCache" runat="server" OnClick="btn_GetData_Click"
Text="從緩衝中讀取資料" />
<asp:Button ID="btn_GetDataFromDb" runat="server" OnClick="btn_GetDataFromDb_Click"
Text="從資料庫中讀取資料" />

第一個按鈕實現從緩衝讀取資料。

注意:本例需要using以下命名空間。

using System.Diagnostics; // 用於精確測定時間間隔
using System.Web.Caching; // 用於緩衝的策略
using System.IO;   // 用於檔案操作

protected void btn_GetData_Click(object sender, EventArgs e)
{
    InsertRecord();
    Stopwatch sw=new Stopwatch();
    sw.Start();
    if (Cache["Data"]==null)
    {
        Response.Write("快取無效判定<br/>");
    }
    else
    {
        DataSet ds = Cache["Data"] as DataSet;
        Response.Write(string.Format("查詢結果:{0}<br/>", ds.Tables[0].Rows[0][0]));
        Response.Write(string.Format("耗費時間:{0}<br/>", sw.ElapsedTicks));
    }
}

在這裡有幾點需要說明。
· 一開始的InsertRecord()方法是我們自己建立的,用來向資料庫插入一條記錄。這樣,我們就能看出來資料是否是從緩衝中讀取的了。
InsertRecord()方法如下:

private void InsertRecord()
{
    using (SqlConnection conn = new SqlConnection(@"server=(local)\SQLEXPRESS;
    database=Forum;Trusted_Connection=True"))
    {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand("Insert into CacheTest (Test) values
       ('Test')", conn))
        {
            cmd.ExecuteNonQuery();
        }
    }
}

· 如果緩衝存在則輸出查詢結果和查詢耗費的時間,如果緩衝不存在則輸出“快取無效判定”。
· Stopwatch類用於精確測定逝去的時間,ElapsedTicks屬性返回了間隔的計數器刻度,所謂計數器刻度就是系統的計數器走過了多少次。當然,Stopwatch還有ElapsedMilliseconds能返回間隔的總毫秒數。之所以使用ElapsedTicks,因為它是一個更小的時間單位。
第二個按鈕直接從資料庫讀取資料。

protected void btn_GetDataFromDb_Click(object sender, EventArgs e)
{
    InsertRecord();
    Stopwatch sw = new Stopwatch();
    sw.Start();
    DataSet ds = GetData();
    Response.Write(string.Format("查詢結果:{0}<br/>", ds.Tables[0].Rows[0][0]));
    Response.Write(string.Format("耗費時間:{0}<br/>", sw.ElapsedTicks));
}

在這裡,我們把讀取資料的操作使用一個GetData()方法進行了封裝,方法實現如下:

private DataSet GetData()
{
    DataSet ds = new DataSet();
    using (SqlConnection conn = new SqlConnection(@"server=(local)\SQLEXPRESS;
    database=Forum;Trusted_Connection=True"))
    {
        SqlDataAdapter da = new SqlDataAdapter("select count(*) from CacheTest", conn);
        da.Fill(ds);           
    }
    return ds;
}

為了能體現出緩衝的效率,我們在Forum資料庫中又建立立了一個CacheTest資料表,表結構很簡單,4-1所示。
 

圖4-1  CacheTest表結構
我們在表中插入了10萬條以上的記錄,使得表的大小達到了100MB左右。
運行程式,單擊“從資料庫中讀取資料”按鈕,4-2所示,

圖4-2 從資料庫讀取資料需要花費大量的時間

我們可以看到,這個操作耗費了相當多的時間。
因為我們直接從資料庫讀取count(*),所以每次單擊按鈕查詢結果顯示的數字都會+1。現在你單擊“從緩衝中讀取資料”肯定是顯示“快取無效判定”,因為我們還沒有添加任何緩衝。
然後,我們在頁面上添加三個按鈕並雙擊按鈕建立事件處理方法,三個按鈕使用不同的到期策略添加緩衝。

<asp:Button ID="btn_InsertNoExpirationCache" runat="server" Text="插入永不到期緩衝"
OnClick="btn_InsertNoExpirationCache_Click" />
<asp:Button ID="btn_InsertAbsoluteExpirationCache" runat="server" Text="插入絕對時間
到期緩衝" OnClick="btn_InsertAbsoluteExpirationCache_Click" />
<asp:Button ID="btn_InsertSlidingExpirationCache" runat="server" Text="插入變化時間
到期緩衝" OnClick="btn_InsertSlidingExpirationCache_Click" />

三個按鈕的Click事件處理方法如下:

protected void btn_InsertNoExpirationCache_Click(object sender, EventArgs e)
{
    DataSet ds = GetData();
    Cache.Insert("Data", ds);
}
protected void btn_InsertAbsoluteExpirationCache_Click(object sender, EventArgs e)
{
    DataSet ds = GetData();
    Cache.Insert("Data", ds,null, DateTime.Now.AddSeconds(10), TimeSpan.Zero);
}
protected void btn_InsertSlidingExpirationCache_Click(object sender, EventArgs e)
{
    DataSet ds = GetData();
    Cache.Insert("Data", ds, null, DateTime.MaxValue, TimeSpan.FromSeconds(10));
}

我們來分析一下這三種到期策略。
· 永不到期。直接賦值緩衝的Key和Value即可
· 絕對時間到期。DateTime.Now.AddSeconds(10)表示緩衝在10秒後到期,TimeSpan.Zero表示不使用平滑到期策略。
· 變化時間到期(平滑到期)。DateTime.MaxValue表示不使用絕對時間到期策略,TimeSpan.FromSeconds(10)表示緩衝連續10秒沒有訪問就到期。
在這裡,我們都使用了Insert()方法來添加緩衝。其實,Cache還有一個Add()方法也能向緩衝中添加項。不同之處在於Add()方法只能添加緩衝中沒有的項,如果添加緩衝中已有的項將失敗(但不會拋出異常),而Insert()方法能覆蓋原來的項。
注意:和Application不同,這裡不需要使用在插入緩衝的時候進行鎖操作,Cache會自己處理     並發。
現在,我們就可以開啟頁面對這三種到期策略進行測試了。
1.單擊“從緩衝中讀取資料”按鈕,提示“快取無效判定”。
2.單擊“從資料庫中讀取資料”按鈕,查詢結果顯示現在記錄總數為100646。
3.單擊“插入永不到期緩衝”按鈕,然後連續單擊“從緩衝中讀取資料”按鈕,可以發現,無論過去多久,緩衝始終沒有到期,而且觀察記錄查詢結果可以發現值始終沒有發生變化。不同的是,從緩衝中讀取資料的效率比從資料庫中讀取資料提高了幾個數量級,4-3所示,你可以和圖4-2進行比較。


圖4-3  從緩衝中讀取資料所花費的時間
4.單擊“插入絕對時間到期緩衝”,然後連續單擊“從緩衝中讀取資料”按鈕,大約10秒到期後,頁面提示“快取無效判定”,說明緩衝到期了。
5.單擊“插入變化時間到期緩衝”,然後連續單擊“從緩衝中讀取資料”按鈕,緩衝始終不到期,如果我們等待10秒後再去單擊按鈕,頁面提示“快取無效判定”,說明緩衝到期了。
我們再來看一下依賴到期策略。所謂依賴到期就是緩衝的依賴項(比如一個檔案)的內容改變之後緩衝也就失效了。由於篇幅關係,這裡只介紹檔案依賴。我們在頁面上再加兩個按鈕並雙擊按鈕添加Click事件處理方法。

<asp:Button ID="btn_ModifyFile" runat="server" Text="修改檔案" OnClick="btn_ModifyFile_
Click" />
<asp:Button ID="btn_AddFileDependencyCache" runat="server" Text="插入檔案依賴緩衝"
OnClick="btn_AddFileDependencyCache_Click" />

在本例中,我們將使緩衝依賴一個txt文字檔。因此,首先在項目中添加一個test.txt文字檔。單擊“修改檔案”按鈕實現檔案的修改。

protected void btn_ModifyFile_Click(object sender, EventArgs e)
{
    FileStream fs = new FileStream(Server.MapPath("test.txt"), FileMode.Append,
    FileAccess.Write);
    StreamWriter sw = new StreamWriter(fs);
    sw.WriteLine(DateTime.Now.ToString());
    sw.Close();
    fs.Close();
}

我們通過在檔案的最後寫入當前的時間來修改檔案。插入檔案依賴緩衝按鈕的事件處理方法如下:

protected void btn_AddFileDependencyCache_Click(object sender, EventArgs e)
{
    CacheDependency cd = new CacheDependency(Server.MapPath("test.txt"));
    DataSet ds = GetData();
    Cache.Insert("Data", ds, cd);
}

添加檔案依賴緩衝同樣簡單,通過CacheDependency關聯了一個檔案依賴。
現在就可以開啟頁面進行測試了。
1.單擊“從緩衝中讀取資料”按鈕,提示“快取無效判定”。
2.單擊“從資料庫中讀取資料”按鈕,查詢結果顯示現在記錄總數為100710。
3.單擊“插入檔案依賴緩衝”按鈕,然後連續單擊“從緩衝中讀取資料”按鈕,可以發現,無論過去多久,緩衝始終沒有到期,而且觀察記錄查詢結果可以發現值始終沒有發生變化。
4.單擊“修改檔案”按鈕,然後單擊“從緩衝中讀取資料”按鈕,提示“快取無效判定”。由於檔案已經修改了,依賴這個檔案的緩衝立刻失效了。
三、  Cache的更新策略

最後,我們來討論緩衝的更新策略。在Web程式中我們通常會使用被動更新。所謂被動更新,就是在調用資料的時候判斷緩衝是否為空白,如果為空白則先更新緩衝然後再從緩衝中讀取資料,如果不為空白則直接從緩衝中讀取資料。可以把“從緩衝中讀取資料”按鈕的Click事件處理方法修改成如下,實現被動更新。

 

protected void btn_GetData_Click(object sender, EventArgs e)
{
    InsertRecord();
    DataSet ds = new DataSet();
    Stopwatch sw = new Stopwatch();
    sw.Start();
    if (Cache["Data"] == null)
    {
        ds = GetData();
        Cache.Insert("Data", ds, null, DateTime.Now.AddSeconds(10), TimeSpan.Zero);
    }
    else
    {
        ds = Cache["Data"] as DataSet;
    }
    Response.Write(string.Format("查詢結果:{0}<br/>", ds.Tables[0].Rows[0][0]));  
    Response.Write(string.Format("耗費時間:{0}<br/>", sw.ElapsedTicks));
}

我們可以看出,如果沒有人訪問資料緩衝是不會更新的,只有緩衝被訪問的時候發現快取無效判定才會去更新。這樣很明顯的一個缺點就是,如果緩衝到期了更新操作將花費很長時間,這個時候的查詢也需要花費很多時間。我們可以利用緩衝的回調功能讓緩衝到期後自動續建實現自動更新的目的。

protected void btn_InsertActiveUpdateCache_Click(object sender, EventArgs e)
{
    DataSet ds = GetData();
    Cache.Insert("Data", ds, null, DateTime.Now.AddSeconds(10), TimeSpan.Zero,
    CacheItemPriority.Default, CacheRemovedCallback);
}

最後一個參數表明緩衝被移除以後自動調用CacheRemovedCallback()方法,方法實現如下。

private void CacheRemovedCallback(String key, object value, CacheItemRemovedReason
removedReason)
{
    DataSet ds = GetData();
    Cache.Insert(key, ds, null, DateTime.Now.AddSeconds(10), TimeSpan.Zero, CacheItemPriority.
    Default, CacheRemovedCallback);
}

在回調方法中,我們再次插入一個支援回調的緩衝。這樣,緩衝被移除以後又能自動更新了。說了這麼多建立緩衝的方法,讀者可能會問怎麼手動移除緩衝呢?比如我們要移除Key="Data"的緩衝只需要:
Cache.Remove("Data");

你可能會馬上想到用Cache.RemoveAll()方法移除所有緩衝,可是Cache沒有提供這樣的方法,我們只能通過遍曆來實現移除所有緩衝。

IDictionaryEnumerator CacheEnum = HttpRuntime.Cache.GetEnumerator();
while (CacheEnum.MoveNext())
{
    Cache.Remove(CacheEnum.Key.ToString());
}
四、  Cache總結

同樣,我們以第一節中的幾個問題結束對Cache的討論。
· 儲存的物理位置。伺服器記憶體。
· 儲存的類型限制。任意類型。
· 狀態使用的範圍。當前請求上下文,所有使用者共用一份。
· 儲存的大小限制。任意大小。
· 生命週期。有多種到期策略控制緩衝的銷毀。
· 安全與效能。資料總是儲存在服務端,安全性比較高,但不易儲存過多資料。
· 優缺點與注意事項。檢索資料速度快,到期策略豐富。注意別把對即時性要求很高的資料放到Cache中,不斷更新Cache會對資料庫造成壓力。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.