CacheDependency 應用以及 Cache 過期時間的最低限制

  • 3916
  • 0

CacheDependency 應用以及 Cache 過期時間的最低限制

dotBlog 的標籤: ,,

遞送電子採購單、領料單等等和物料有關的表單時,通常都必須檢核請領產品是否為特殊管制物品,並做相對應的處理,但是產品有數十萬項,因此不可能快取所有產品,但是若使用者在同一次上線作業中,遞送表單有上百筆,但是裡面有許多重複的品項,每一筆都連線到資料庫去檢查是否為管制物品,根本就意圖謀殺資料庫,所以較好的方式就是做短時間的產品資料快取,而且同時設定快取的未使用過期時間和絕對過期時間,節省伺服器資源。

頁面放計時器,為了方便測試和顯示快取資料:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:Timer ID="Timer1" runat="server" Interval="1000" ontick="Timer1_Tick">
        </asp:Timer>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
            <ContentTemplate>
                現在時間:<asp:Label ID="lblTime" runat="server"></asp:Label>
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" />
            </Triggers>
        </asp:UpdatePanel>
        <p>
        ProductFlag:<asp:Label ID="lblProp" runat="server"></asp:Label>
        <asp:Button ID="btnRefresh" runat="server" Text="取得ProductFlag" 
                onclick="btnRefresh_Click" />
        </p>
        Cache更新時間:<asp:Label ID="lblCacheTime" runat="server"></asp:Label>
    
    </div>
    </form>
</body>
</html>

程式碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
    //假裝是資料庫查回來的值
    private static bool _ProductFlag = false;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack) { lblProp.Text = ShowProductFlag("假的ID").ToString(); }
    }

    protected bool ShowProductFlag(string ID)
    {
        Dictionary<string, bool> MaterialFlag;
        //初始化快取資料
        MaterialFlag = Cache.Get("ProductFlagCache") == null ?
            new Dictionary<string, bool>() :
            (Dictionary<string, bool>)Cache.Get("ProductFlagCache");
        //若ID不存在於快取中,就去資料庫查回來,並更新快取資料
        if (MaterialFlag.ContainsKey(ID) == false)
        {
            //快取的絕對過期時間,因為不能同時設定絕對過期和相對過期時間,
            //所以要再透過CacheDependency做快取相依性設定
            //請注意,同時設定絕對過期和相對過期,編譯不會有錯,執行時間才會死掉
            MaterialFlag.Add(ID, GetProductFlag(ID));
            Cache.Insert("ExpireFlag", DateTime.Now, null,
                DateTime.Now.AddSeconds(40), Cache.NoSlidingExpiration);
            //透過CacheDependency設定要相依的快取索引名稱(可以很多個,所以是陣列)
            CacheDependency cd = new CacheDependency(null, new string[] { "ExpireFlag" });
            Cache.Insert("ProductFlagCache", MaterialFlag, cd,
                Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(10));
            lblCacheTime.Text = DateTime.Now.ToLongTimeString();
        }

        return MaterialFlag[ID];
    }

    /// <summary>
    /// 假裝回資料庫查,每次查詢後就把值給換掉。
    /// </summary>
    /// <param name="ID">The ID.</param>
    protected bool GetProductFlag(string ID)
    {
        bool result = _ProductFlag;
        _ProductFlag = !_ProductFlag;

        return result;
    }

    protected void Timer1_Tick(object sender, EventArgs e)
    {
        lblTime.Text = DateTime.Now.ToLongTimeString();
    }

    protected void btnRefresh_Click(object sender, EventArgs e)
    {
        lblProp.Text = ShowProductFlag("假的ID").ToString();
    }
}

範例畫面:

020603

同場加映:一開始測試時,我為了快速測試,就把絕對過期時間設定為 10 秒,結果發現要到 20 秒才會過期重新寫快取資料,改成 5 秒、15 秒,也都一樣要 20 秒才會過期,百思不得其解,程式也都正確,後來終於查到,這是 .Net Fremework 寫死在 CacheExpires 的建構式中:

_tsPerBucket = new TimeSpan(0, 0, 20);

而且還是唯讀……換言之,絕對過期時間請設定 20 秒的倍數吧,而且不能低於 20 秒,因為它每 20 秒才會檢查有無過期。此問題確認原因後,我沒繼續查怎麼解決,一則是 20 秒我可以接受,一則是:我想睡了 zzz ZZZ

--------
沒什麼特別的~
不過是一些筆記而已