自定义缓存应用程序块中的一个缓存过期依赖项
一、在添加一个缓存项时,允许指定一个过期策略,这个过期策略对象要实现ICacheItemExpiration接口,常见的过期策略有:
绝对过期时间 : AbsoluteTime
表达式表示的时间过期策略:ExtendedFormatTime
程序运行中一直不会过期NeverExpired:
每次读取之后,再延长指定的时间后才会过期:SlidingTime。
文件依赖:FileDependency
二、自己实现一个,缓存项依赖:CacheItemDependency
参考FileDependency的实现,缓存项的过期与否取决于文件是否发生了变化,我们自己实现一个过期策略,就是缓存项的过期与否取决于另一个NeverExpired的缓存项是否发生了变化。
代码如下:
Code
[Serializable]
[ComVisible(false)]
public class CacheItemDependency : ICacheItemExpiration
{
private readonly string dependencyCacheKey;
private System.Int32 lastCount;
Constructor#region Constructor
/**//// <summary>
/// Constructor with one argument.
/// </summary>
/// <param name="cacheKey">Indicates the key of the cache item</param>
public CacheItemDependency(string cacheKey)
{
dependencyCacheKey = cacheKey;
ICacheManager cacheManager = CacheFactory.GetCacheManager();
lastCount = Int32.MinValue;
if (cacheManager != null)
{
if (cacheManager.Contains(cacheKey))
{
object o = cacheManager.GetData(cacheKey);
if (o != null)
{
this.lastCount = (int)o;
}
lastCount = (int)cacheManager.GetData(cacheKey);
}
else
{
cacheManager.Add(cacheKey, lastCount);
}
}
}
#endregion
Properties#region Properties
/**//// <summary>
/// Gets the key of the dependent Cache Item.
/// </summary>
/// <value>
/// The key of the dependent Cache Item.
/// </value>
public string DependencyCacheKey
{
get { return dependencyCacheKey; }
}
/**//// <summary>
/// Gets the Last Count.
/// </summary>
/// <value>
/// The Count of the last setup.
/// </value>
public System.Int32 LastCount
{
get { return lastCount; }
}
#endregion
ICacheItemExpiration Members#region ICacheItemExpiration Members
/**//// <summary>
/// Specifies if the item has expired or not.
/// </summary>
/// <returns>Returns true if the item has expired, otherwise false.</returns>
public bool HasExpired()
{
ICacheManager cacheManager = CacheFactory.GetCacheManager();
//throw new Exception("The method or operation is not implemented.");
if (cacheManager == null)
{
return true;
}
System.Int32 currentCount = (int)cacheManager.GetData(dependencyCacheKey);
if (currentCount != lastCount)
{
return true;
}
else
{
return false;
}
}
/**//// <summary>
/// Notifies that the item was recently used.
/// </summary>
public void Notify()
{
}
/**//// <summary>
/// Not used
/// </summary>
/// <param name="owningCacheItem">Not used</param>
public void Initialize(CacheItem owningCacheItem)
{
}
#endregion
}
[Serializable]
[ComVisible(false)]
public class CacheItemDependency : ICacheItemExpiration
{
private readonly string dependencyCacheKey;
private System.Int32 lastCount;
Constructor#region Constructor
/**//// <summary>
/// Constructor with one argument.
/// </summary>
/// <param name="cacheKey">Indicates the key of the cache item</param>
public CacheItemDependency(string cacheKey)
{
dependencyCacheKey = cacheKey;
ICacheManager cacheManager = CacheFactory.GetCacheManager();
lastCount = Int32.MinValue;
if (cacheManager != null)
{
if (cacheManager.Contains(cacheKey))
{
object o = cacheManager.GetData(cacheKey);
if (o != null)
{
this.lastCount = (int)o;
}
lastCount = (int)cacheManager.GetData(cacheKey);
}
else
{
cacheManager.Add(cacheKey, lastCount);
}
}
}
#endregion
Properties#region Properties
/**//// <summary>
/// Gets the key of the dependent Cache Item.
/// </summary>
/// <value>
/// The key of the dependent Cache Item.
/// </value>
public string DependencyCacheKey
{
get { return dependencyCacheKey; }
}
/**//// <summary>
/// Gets the Last Count.
/// </summary>
/// <value>
/// The Count of the last setup.
/// </value>
public System.Int32 LastCount
{
get { return lastCount; }
}
#endregion
ICacheItemExpiration Members#region ICacheItemExpiration Members
/**//// <summary>
/// Specifies if the item has expired or not.
/// </summary>
/// <returns>Returns true if the item has expired, otherwise false.</returns>
public bool HasExpired()
{
ICacheManager cacheManager = CacheFactory.GetCacheManager();
//throw new Exception("The method or operation is not implemented.");
if (cacheManager == null)
{
return true;
}
System.Int32 currentCount = (int)cacheManager.GetData(dependencyCacheKey);
if (currentCount != lastCount)
{
return true;
}
else
{
return false;
}
}
/**//// <summary>
/// Notifies that the item was recently used.
/// </summary>
public void Notify()
{
}
/**//// <summary>
/// Not used
/// </summary>
/// <param name="owningCacheItem">Not used</param>
public void Initialize(CacheItem owningCacheItem)
{
}
#endregion
}
三、使用方法
1、更新缓存所依赖的缓存项。代码如下:
Code
/**//// <summary>
/// 更新所有以cacheKeys中元素为key的缓存项
/// </summary>
/// <param name="cacheKeys">缓存项的key的数组</param>
public static void UpdateCacheDependency(string[] cacheKeys)
{
ICacheManager cacheManager = CacheFactory.GetCacheManager();
foreach (string cacheKey in cacheKeys)
{
string cacheItemCache = GetCacheKey(cacheKey);
if (cacheManager != null && cacheManager.Contains(cacheItemCache))
{
int lastCount = (int)cacheManager.GetData(cacheItemCache);
if (lastCount < Int32.MaxValue)
{
lastCount++;
}
else
{
lastCount = Int32.MinValue;
}
// 这一句的作用在于更新以cacheKey为key的缓存项,从而使依赖于此缓存项的缓存项失效.
// 当以cacheKey为Key的缓存项中的数据(这里是lastCount)变化时,是的依赖于此缓存项的缓存失效
cacheManager.Add(cacheKey, lastCount);
}
}
}
/**//// <summary>
/// 更新所有以cacheKeys中元素为key的缓存项
/// </summary>
/// <param name="cacheKeys">缓存项的key的数组</param>
public static void UpdateCacheDependency(string[] cacheKeys)
{
ICacheManager cacheManager = CacheFactory.GetCacheManager();
foreach (string cacheKey in cacheKeys)
{
string cacheItemCache = GetCacheKey(cacheKey);
if (cacheManager != null && cacheManager.Contains(cacheItemCache))
{
int lastCount = (int)cacheManager.GetData(cacheItemCache);
if (lastCount < Int32.MaxValue)
{
lastCount++;
}
else
{
lastCount = Int32.MinValue;
}
// 这一句的作用在于更新以cacheKey为key的缓存项,从而使依赖于此缓存项的缓存项失效.
// 当以cacheKey为Key的缓存项中的数据(这里是lastCount)变化时,是的依赖于此缓存项的缓存失效
cacheManager.Add(cacheKey, lastCount);
}
}
}
2、每次更新数据库中的表时,调用UpdateCacheDependency方法。
在上述代码中cacheKey可以用数据库中标的名称。
还有一个问题就是 每次更新数据库中的表时,都要调用UpdateCacheDependency方法,是不是很烦,这也是没有办法的,必须调用,否则 依赖于 以cacheKey为Key的缓存项 的缓存项 不会失效,一般可以在数据访问的基类中将Insert\Update\Delete执行的地方调用这个方法即可。
如果用DataSet,代码类似这样:
Code
public int Update(DataSet dataSet, bool isStoredProc, bool removeCache, string[] cacheItemKeys)
{
int cnt = db.UpdateDataSet(dataSet, dataSet.Tables[0].TableName,
PrepareCommand(insertCommand, InsertStoredProc, new PopulateParameters(PopulateInsertParamters), isStoredProc),
PrepareCommand(updateCommand, UpdateStoredProc, new PopulateParameters(PopulateUpdateParamters), isStoredProc),
PrepareCommand(deleteCommand, DeleteStoredProc, new PopulateParameters(PopulateDeleteParamters), isStoredProc),
UpdateBehavior.Standard);
if (removeCache && cacheItemKeys != null)
{
DataAccessUtil.UpdateCacheDependency(cacheItemKeys);
}
return cnt;
}
public int Update(DataSet dataSet, bool isStoredProc, bool removeCache, string[] cacheItemKeys)
{
int cnt = db.UpdateDataSet(dataSet, dataSet.Tables[0].TableName,
PrepareCommand(insertCommand, InsertStoredProc, new PopulateParameters(PopulateInsertParamters), isStoredProc),
PrepareCommand(updateCommand, UpdateStoredProc, new PopulateParameters(PopulateUpdateParamters), isStoredProc),
PrepareCommand(deleteCommand, DeleteStoredProc, new PopulateParameters(PopulateDeleteParamters), isStoredProc),
UpdateBehavior.Standard);
if (removeCache && cacheItemKeys != null)
{
DataAccessUtil.UpdateCacheDependency(cacheItemKeys);
}
return cnt;
}
如果用实体类,代码类似这样:
Code
protected bool ExecuteNonQuery(TEntity entity, string spName, PopulateParamters<TEntity> populateParamters, HandleReturnValue handleReturnValue, bool removeCache, string[] cacheKeys)
{
int returnValue = -1;
try
{
Database db = DatabaseFactory.CreateDatabase();
DbCommand cmd = db.GetStoredProcCommand(spName);
if (populateParamters != null)
{
populateParamters(entity, db, cmd);
}
if (handleReturnValue != null)
{
db.AddParameter(cmd, "ReturnValue", DbType.Int32, ParameterDirection.ReturnValue, String.Empty, DataRowVersion.Default, null);
}
db.ExecuteNonQuery(cmd);
returnValue = 0;
if (handleReturnValue != null)
{
returnValue = DataAccessHelper.GetReturnValue(db, cmd);
handleReturnValue(returnValue, "");
}
}
catch
{
throw;
}
if (removeCache && cacheKeys != null && cacheKeys.Length > 0)
{
UpdateCacheDependency(cacheKeys);
}
return (returnValue == 0);
}
protected bool ExecuteNonQuery(TEntity entity, string spName, PopulateParamters<TEntity> populateParamters, HandleReturnValue handleReturnValue, bool removeCache, string[] cacheKeys)
{
int returnValue = -1;
try
{
Database db = DatabaseFactory.CreateDatabase();
DbCommand cmd = db.GetStoredProcCommand(spName);
if (populateParamters != null)
{
populateParamters(entity, db, cmd);
}
if (handleReturnValue != null)
{
db.AddParameter(cmd, "ReturnValue", DbType.Int32, ParameterDirection.ReturnValue, String.Empty, DataRowVersion.Default, null);
}
db.ExecuteNonQuery(cmd);
returnValue = 0;
if (handleReturnValue != null)
{
returnValue = DataAccessHelper.GetReturnValue(db, cmd);
handleReturnValue(returnValue, "");
}
}
catch
{
throw;
}
if (removeCache && cacheKeys != null && cacheKeys.Length > 0)
{
UpdateCacheDependency(cacheKeys);
}
return (returnValue == 0);
}