緩存機制理解及C#開發使用


      隨着Web的迅猛發展,從1.0、2.0再到現在的3.0無論是硬件還是軟件對它的支持都是巨大的,這個過程中很多IT大佬提出了非常牛的定律,像摩爾定律、吉爾德定律、麥特卡爾定律、貝爾定律等,整個IT的發展也是按照這4大定律的驅使,像這個摩爾定律和貝爾定律大體是說我們用到的像電腦等硬件每18個月性能就會提高一倍,也就是說18個月前你花6000買的電腦現在3000就能買到同樣配置的,吉爾德定律和麥特卡爾定律是說我們現在用到的寬帶會越來越不值錢,可能以后會免費,后續那些牛的企業或人都是利用寬帶的IT精英們,這個確實是這樣的,像我們這些做軟件開發的誰能離開網絡?在這個過程中我所理解的web也從最簡單的HTML進化到富客戶端,然后到插件化、信息發布、服務的方式,這個過程中產生了很多新技術,AJAX、Flash\Silverligth\Flex、REST\WebService、微件(Widgets)、WebCache、靜態化等,這些新技術也是伴隨着硬件的提升而產生的,像我今天探討的這個WebCache就是硬件的提升帶來的,WebCache我們最直觀的理解就是頁面緩存,是放在內存中的,像6年前那時候咱們的電腦或普通服務器的內存都不會超過1G,所以說即使有這個技術也不會在國內流行起來,而現在就不一樣了,我們隨便配置個筆記本現在標配內存都是8個G,不好好利用一下才怪呢,我們的系統從內存中讀取數據的速度比從硬盤中讀取不是一個等量級的,那是相當的快,所以緩存就隨着而來,最近我做的幾個大型的BS網站都用到了它,它的確好用,能提高網站的整體性能,提高訪問速度,減少數據庫的連接數和性能損耗,這里我們就從緩存的概念、使用場景、asp.net開發中如何應用緩存、緩存的技術特點等4方面去深入了解它。

      通常的了解是我們的應用程序可以將那些頻繁訪問的數據,以及那些需要大量處理時間來創建的數據存儲在內存中,從而提高性能,這就是頁面緩存的通俗理解,它主要包括應用程序緩存和頁輸出緩存,應用程序緩存提供了一種編程方式,可通過鍵/值對將任意數據存儲在內存中,頁輸出緩存則是在內存中存儲處理后的 ASP.NET 頁的內容。

      緩存的使用場景主要總結了3個方面,一是研發模塊比較穩定,研發模塊比較穩定,讀取數據比較頻繁,更新數據頻率低;二是歷史數據查詢、報表統計等;三是部分頁面級緩存(像自定義控件)。

      理解了頁面緩存的概念之后,我們就可以用簡單的編碼例子去幫助理解了,首先我們可以對asp.net的緩存System.Web.Caching.Cache進行一下封裝,主要是對微軟提供的緩存進行操作,這里我們用設計模式的理念出發,我們是面向接口編程的,接口名稱為公共緩存策略接口ICacheStrategy,主要對方法進行規范包括增、刪、改、查、過期等,見如下代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Caching;

namespace FrameWork
{
    /// <summary>
    /// 公共緩存策略接口
    /// </summary>
    public interface ICacheStrategy
    {
        /// <summary>
        /// 添加指定ID的對象
        /// </summary>
        /// <param name="objId"></param>
        /// <param name="o"></param>
        void AddObject(string objID, object o);
        /// <summary>
        /// 添加指定ID的對象
        /// </summary>
        /// <param name="objId"></param>
        /// <param name="o"></param>
        /// <param name="timeOut">過期時間</param>
        void AddObject(string objId, object o, int timeOut);
        /// <summary>
        /// 添加指定ID的對象(關聯指定文件組)
        /// </summaryICacheStrategy
        /// <param name="objId"></param>
        /// <param name="o"></param>
        /// <param name="files"></param>
        void AddObjectWithFileChange(string objId, object o, params string[] files);
        /// <summary>
        /// 添加指定ID的對象(關聯指定文件組)
        /// </summaryICacheStrategy
        /// <param name="objId"></param>
        /// <param name="o"></param>
        /// <param name="files"></param>
        void AddObjectWithFileChange(string objId, object o, CacheItemRemovedCallback callback, params string[] files);
        /// <summary>
        /// 添加指定ID的對象(關聯指定鍵值組)
        /// </summary>
        /// <param name="objId"></param>
        /// <param name="o"></param>
        /// <param name="dependKey"></param>
        void AddObjectWithDepend(string objId, object o, params string[] dependKey);
        /// <summary>
        /// 移除指定ID的對象
        /// </summary>
        /// <param name="objId"></param>
        void RemoveObject(string objId);
        /// <summary>
        /// 返回指定ID的對象
        /// </summary>
        /// <param name="objId"></param>
        /// <returns></returns>
        object RetrieveObject(string objId);
        /// <summary>
        /// 返回指定ID的對象
        /// </summary>
        /// <param name="objId"></param>
        /// <returns></returns>
        T RetrieveObject<T>(string objId);
        /// <summary>
        /// 到期時間,單位:秒
        /// </summary>
        int TimeOut { set; get; }
    }
}

接口定義了之后,我們建一個默認緩存管理類DefaultCacheStrategy去實現這個接口,這里我們可以用單例模式,讓這個緩存類在整個應用中只有一個實例,見代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Caching;

namespace FrameWork
{
    /// <summary>
    /// 默認緩存管理類
    /// </summary>
    public class DefaultCacheStrategy : ICacheStrategy
    {
        private static readonly DefaultCacheStrategy instance = new DefaultCacheStrategy();
        protected static volatile System.Web.Caching.Cache webCache = System.Web.HttpRuntime.Cache;

        /// <summary>
        /// 默認緩存存活期為3600秒(1小時)
        /// </summary>
        protected int _timeOut = 3600;

        static DefaultCacheStrategy()
        { }

        /// <summary>
        /// 設置到期相對時間[單位: 秒] 
        /// </summary>
        public virtual int TimeOut
        {
            set {_timeOut=value>0?value:3600;}
            get{return _timeOut>0?_timeOut:3600;}
        }
        /// <summary>
        ///  獲取當前應用程序的 System.Web.Caching.Cache
        /// </summary>
        public static System.Web.Caching.Cache GetWebCacheObj
        {
            get { return webCache; }
        }
        public virtual void AddObject(string objId, object o)
        {
            if (objId == null || objId.Length == 0 || o == null)
            {
                return;
            }

            CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove);
            if (TimeOut == 7200)
            {
                webCache.Insert(objId, o, null, DateTime.MaxValue, TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, callBack);
            }
            else
            {
                webCache.Insert(objId, o, null, DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack);
            }
        }

        /// <summary>
        /// 加入當前對象到緩存中
        /// </summary>
        /// <param name="objId">對象的鍵值</param>
        /// <param name="o">緩存的對象</param>
        public virtual void AddObjectWith(string objId, object o)
        {
            if (objId == null || objId.Length == 0 || o == null)
            {
                return;
            }

            CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove);

            webCache.Insert(objId, o, null, System.DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack);
        }

        /// <summary>
        /// 加入當前對象到緩存中,並對相關文件建立依賴
        /// </summary>
        /// <param name="objId">對象的鍵值</param>
        /// <param name="o">緩存的對象</param>
        /// <param name="files">監視的路徑文件</param>
        public virtual void AddObjectWithFileChange(string objId, object o, params string[] files)
        {
            if (objId == null || objId.Length == 0 || o == null)
            {
                return;
            }
            CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove);
            CacheDependency dep = new CacheDependency(files, DateTime.Now);

            webCache.Insert(objId, o, dep, System.DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack);
        }

        /// <summary>
        /// 加入當前對象到緩存中,並對相關文件建立依賴
        /// </summary>
        /// <param name="objId">對象的鍵值</param>
        /// <param name="o">緩存的對象</param>
        /// <param name="files">監視的路徑文件</param>
        public virtual void AddObjectWithFileChange(string objId, object o, CacheItemRemovedCallback callback, params string[] files)
        {
            if (objId == null || objId.Length == 0 || o == null)
            {
                return;
            }

            CacheDependency dep = new CacheDependency(files, DateTime.Now);

            webCache.Insert(objId, o, dep, System.DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callback);
        }

        /// <summary>
        /// 加入當前對象到緩存中,並使用依賴鍵
        /// </summary>
        /// <param name="objId">對象的鍵值</param>
        /// <param name="o">緩存的對象</param>
        /// <param name="dependKey">依賴關聯的鍵值</param>
        public virtual void AddObjectWithDepend(string objId, object o, params string[] dependKey)
        {
            if (objId == null || objId.Length == 0 || o == null)
            {
                return;
            }

            CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove);

            CacheDependency dep = new CacheDependency(null, dependKey, DateTime.Now);

            webCache.Insert(objId, o, dep, System.DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack);
        }

        public void onRemove(string key, object value, CacheItemRemovedReason reason)
        {
            switch (reason)
            {
                case CacheItemRemovedReason.DependencyChanged:
                    break;
                case CacheItemRemovedReason.Expired:
                    {
                        //CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(this.onRemove);

                        //webCache.Insert(key, val, null, System.DateTime.Now.AddMinutes(TimeOut),
                        //    System.Web.Caching.Cache.NoSlidingExpiration,
                        //    System.Web.Caching.CacheItemPriority.High,
                        //    callBack);
                        break;
                    }
                case CacheItemRemovedReason.Removed:
                    {
                        break;
                    }
                case CacheItemRemovedReason.Underused:
                    {
                        break;
                    }
                default: break;
            }
        }
        /// <summary>
        /// 刪除緩存對象
        /// </summary>
        /// <param name="objId">對象的關鍵字</param>
        public virtual void RemoveObject(string objId)
        {
            if (objId == null || objId.Length == 0)
            {
                return;
            }
            webCache.Remove(objId);
        }

        /// <summary>
        /// 返回一個指定的對象
        /// </summary>
        /// <param name="objId">對象的關鍵字</param>
        /// <returns>對象</returns>
        public virtual object RetrieveObject(string objId)
        {
            if (objId == null || objId.Length == 0)
            {
                return null;
            }
            return webCache.Get(objId);
        }
        /// <summary>
        /// 返回指定ID的對象
        /// </summary>
        /// <param name="objId"></param>
        /// <typeparam name="T">返回數據的類型</typeparam>
        /// <returns></returns>
        public virtual T RetrieveObject<T>(string objId)
        {
            object o = RetrieveObject(objId);
            return o != null ? (T)o : default(T);
        }


        public void AddObject(string objId, object o, int timeOut)
        {
            if (String.IsNullOrEmpty(objId) || String.IsNullOrEmpty(objId.Trim()))
                return;

            CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove);
            if (timeOut > 0)
            {
                webCache.Insert(objId, o, null, DateTime.Now.AddMilliseconds(timeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack);
            }
            else
            {
                webCache.Insert(objId, o, null, DateTime.MaxValue, TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, callBack);
            }
        }



    }
}

這個類主要是對System.Web.Caching.Cache webCache這個實際的緩存進行封裝的,我們封裝出來之后一是為了方便使用,另外就是為了研發的規范性,避免了研發人員自行對微軟自己的緩存進行研究及調用,頁面調用參考代碼:

DefaultCacheStrategy dcs = new DefaultCacheStrategy();
            dcs.AddObject("1111", "緩存的實際內容");
            this.lblTest.Text = dcs.RetrieveObject<string>("1111");

       講完了緩存的開發方式,我們可以總結一下緩存的技術特點了,我總結有4條:一是減少數據庫的訪問次數;二是提高應用的性能;三是增強用戶的體驗;四是提高應用的訪問速度。


免責聲明!

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



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