正如您已经发现的那样,将 GUID 用于缓存键并不是一个好的解决方案。主要问题是生成 GUID 后,没有办法可靠地将其重新生成为相同的键,以便将数据从缓存中取出。
通常,当我创建缓存时,键基于被缓存的实体或缓存它的方法。但也可以基于使值唯一的值组合来制作缓存。
使用实体的示例
public class Employee
{
int Id { get; set; }
string Name { get; set; }
}
要从实体中获取键,我们只需在实体的主键之外使用一个常量值。
private const string KEY_PREFIX = "Employee_";
private object syncLock = new object();
// innerEmployeeRetriever and cache are populated through the constructor
public Employee GetEmployee(int id)
{
string key = KEY_PREFIX + id.ToString();
// Get the employee from the cache
var employee = cache[key];
if (employee == null)
{
lock (syncLock)
{
// Double-check that another thread didn't beat us
// to populating the cache
var employee = cache[key];
if (employee == null)
{
employee = innerEmployeeRetriever.GetEmployee(id);
cache[key] = employee;
}
}
}
return employee;
}
使用方法名称的示例
private object syncLock = new object();
// innerEmployeeRetriever and cache are populated through the constructor
public Employee GetEmployeeList()
{
string key = "GetEmployeeList";
// Get the employee from the cache
var employees = cache[key];
if (employees == null)
{
lock (syncLock)
{
// Double-check that another thread didn't beat us
// to populating the cache
var employees = cache[key];
if (employees == null)
{
employees = innerEmployeeRetriever.GetEmployeeList();
cache[key] = employees;
}
}
}
return employees;
}
使用值组合的示例
您还可以从几个不同的值构建键,这些值组合起来使实体独一无二。如果您没有可使用的主键,或者您有几个不同的上下文要分别缓存,这将很有帮助。这个例子取自MvcSiteMapProvider:
protected string GetCacheKey(string memberName)
{
// NOTE: We must include IsReadOnly in the request cache key
// because we may have a different
// result when the sitemap is being constructed than when
// it is being read by the presentation layer.
return "__MVCSITEMAPNODE_" + this.SiteMap.CacheKey + "_" + this.Key
+ "_" + memberName + "_" + this.IsReadOnly.ToString() + "_";
}
在这种情况下,我们根据节点所属的父 SiteMap 的唯一键、节点的唯一键、方法或属性名称以及当前是否设置了只读标志来构建键。这些值的每一个唯一集合都会产生一个单独的缓存键,从而为每个组合创建一个单独的缓存。
当然,要使其正常工作,值之间应该有某种“安全”分隔符,以防止通过连接不同的值来创建相同的键。例如,"1" + "23" 与 "12" + "3" 是相同的字符串,但您可以通过使用下划线、竖线字符、逗号或其他一些不在数据本身中的分隔符来分隔值来防止此类冲突("1" + "_" + "23" 与"12" + "_" + "3"不是相同的字符串)。
底线是缓存键必须以某种方式表示缓存中的什么才能使其有用。您的应用程序应了解如何提供构成密钥的数据,以便在需要再次检索相同数据时重新生成密钥。