在許多項目應用中,我們設計的資料庫中的一些表中的資料變化的頻率很慢,比如,我們有個GameInformation表儲存所有已上線的遊戲的資訊,這個表中的資料變動的頻率就很小(因為可能一兩個月才會有個新遊戲上線或偶爾修改一下已上線遊戲的具體資訊(通常都是不需緊急更新的)),而且,這個表中的資料又經常被用到,比如根據GameID擷取遊戲的名字、簡介等等。這種表就很適合緩衝在記憶體中,這樣可以提供更好的效能和有效地降低資料庫的負載。
DataRabbit.Application.Cache命名空間提供了對Entity緩衝的支援,並且能夠定時重新整理緩衝(如每隔15分鐘重新整理一次)。
首先,在架構中,Entity緩衝(EntityCache)是通用Cache的一種,我們來看看,架構對緩衝(ESBasic.Cache.ICache介面)的定義: public interface ICache
{
bool Enabled { get;set; }
void Initialize();
void Refresh();
event CbSimple CacheRefreshed;
}
其次,ESBasic.Cache命名空間下有個ICacheManager,它用於管理所有緩衝(Cache)執行個體,而且定時重新整理每個緩衝的功能也是它提供的。其介面定義如下:public interface ICacheManager
{
/// <summary>
/// RefreshSpanInSecs 定時重新整理緩衝的時間間隔
/// </summary>
int RefreshSpanInSecs { set; }
IList<ICache> CacheList { set; }
void Initialize();
void RefreshNow();
void AddCache(ICache cache);
void RemoveCache(ICache cache);
void RemoveCaches();
event CbCacheException CacheRefreshFailed;
}
ESBasic.Cache.CacheManager類實現了該介面。
現在,有了基礎緩衝介面和緩衝管理器的支援,我們就可以在其基礎上實作實體緩衝(EntityCache)。
首先,一個實體Entity要能被緩衝,該Entity必須實現ICachedEntity泛型介面: /// <summary>
/// ICachedEntity 可以被緩衝的Entity
/// </summary>
/// <typeparam name="TPKey">主鍵的類型</typeparam>
public interface ICachedEntity<TPKey>
{
TPKey GetID();
}
那麼,實體緩衝可以提供哪些操作了?簡單想一下,我們就可以知道,比如擷取所有緩衝的Entity,根據ID擷取Entity,等等。IEntityCache介面中定義了這些功能: /// <summary>
/// IEntityCache 從資料庫中擷取合格Entity並緩衝起來。2007.07.07
/// </summary>
/// <typeparam name="TPKey">對應的資料表的主鍵類型</typeparam>
/// <typeparam name="TEntity">Entity類型</typeparam>
public interface IEntityCache<TPKey, TEntity> : ICache where TEntity : class, ICachedEntity<TPKey>
{
/// <summary>
/// GetEntity 擷取目標Entity,如果緩衝中不存在,則重新整理緩衝,如果還招不到,則返回null。
/// </summary>
TEntity GetEntity(TPKey entityID);
IList<TEntity> GetEntityList();
TransactionScopeFactory TransactionScopeFactory { set; }
CacheRefreshMode CacheRefreshMode { set; }
}
/// <summary>
/// CacheRefreshMode 緩衝重新整理模式:全部替換、增量。
/// </summary>
public enum CacheRefreshMode
{
ReplaceAll ,
Increasement
}
DataRabbit.Application.Cache.EntityCache類實現了該介面,並且提供了虛方法CreateFilterTree來讓衍生類別來提供一系列條件,只有符合這些條件的Entity才會從資料庫中取出來緩衝。CreateFilterTree方法定義如下:
#region CreateFilterTree
/// <summary>
/// SetFilterTree 衍生類別可以通過此方法設定要緩衝的對象的條件,返回null,表示緩衝表中的所有Entity
/// </summary>
protected virtual IFilterTree CreateFilterTree()
{
return null;
}
#endregion
下面舉一個例子來說明實體緩衝的應用。
比如,我需要緩衝所有啟用的GameInformation。
首先,讓GameInformation實體類從ICachedEntity繼承: public partial class GameInformation : ICachedEntity<string>
{
//
}
GameInformation表的主鍵ID是字串類型。
接下來,從DataRabbit.Application.Cache.EntityCache繼承得到具體的緩衝類GameInfoCache: public class GameInfoCache :EntityCache<string ,GameInformation>
{
protected override IFilterTree CreateFilterTree()
{
//取出所有啟用的遊戲資訊
return new SimpleFilterTree(LogicType.And, new Filter(GameInformation._Enabled, true));
}
}
最後,我們通過Spring.net來配置緩衝管理器和實體緩衝即可,假設我們讓緩衝管理器每15分鐘(900s)重新整理一次。<object name="gameInfoCache" type="GameRabbit.Entity.Cache.GameInfoCache,GameRabbit.Entity" init-method="Initialize">
<property name="Enabled" value="true"/>
<property name="TransactionScopeFactory" ref="transactionScopeFactory"/>
<property name="CacheRefreshMode" value="ReplaceAll"/>
</object>
<object name="cacheManager" type="ESBasic.Cache.CacheManager ,ESBasic" init-method="Initialize">
<property name="RefreshSpanInSecs" value="900"/>
<property name="CacheList">
<list element-type="ESBasic.Cache.ICache,ESBasic">
<ref object="gameInfoCache"/>
</list>
</property>
</object>
如此即可。上述的介紹不僅用到的DataRabbit中的類,而且也用到了ESBasic中的相關組件,不用擔心,我在DataRabbit 輕量的ORM架構(00) -- 序 一文的末尾提供的DataRabbit3.0下載中包含了必須的ESBasic動態庫。可以從那裡下載,來試試EntityCache的方便性。