在许多项目应用中,我们设计的数据库中的一些表中的数据变化的频率很慢,比如,我们有个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
=
"g
ameInfoCache
"
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的方便性。