请记住,我在这里展示的示例仅用于尽可能清楚地解释问题,而不是任何实际的实现或生产代码。
另外,我们假设如果从后端存储或返回任何内容,它将被缓存。我在代码中省略了如何以及在何处发生的示例。
对于这个问题的范围,我们还必须假设,MyType集合总是很小,相当静态,当应用程序启动时,它将从后端获取所有内容并重用缓存副本直到应用程序关闭。这就是GetCached(id)
和GetBackend(id)
实际上只是ListCached
和ListBackend
的包装的原因。
假设我们有以下类型的简单存储库:
public class MyRepository : IRepository<MyType>
{
public IEnumerable<MyType> GetAll()
{
// Will return cached items if present
return ListCached ?? ListBackend;
}
public MyType Get(int id)
{
return GetCached(id) ?? GetBackend(id);
}
private MyType GetBackend(int id)
{
return ListBackend.FirstOrDefault(type => type.Id == id);
}
private MyType GetCached(int id)
{
return ListCached.FirstOrDefault(type => type.Id == id);
}
protected IEnumerable<MyType> ListBackend
{
get { return Backend.GetAll<MyType>(); }
set { Backend.StoreAll<MyType>(value); }
}
public IEnumerable<MyType> ListCached
{
get { return Cache.GetAll<MyType>(); }
set { Cache.StoreAll<MyType>(value); }
}
public void Store(MyType value)
{
Backend.Store(value);
}
}
这就是挑战:
class Program
{
static void Main(string[] args)
{
#region Handling Missing Objects in Cache
// We have a repository
var rep = new MyRepository();
// Into which we put stuff (3 for the demo)
rep.Store(new MyType { Id = 1 });
rep.Store(new MyType { Id = 2 });
rep.Store(new MyType { Id = 3 });
// And the repository, after this, returns 3 items
// The items are returned from cache
var count = rep.GetAll().Count(); // Returns 3
// However, somewhere else in the application, it happens so,
// for any reason, bug, programmer error, photon from sun hitting the cpu
// or tinfoil-hat left home in rush,
// that one item gets removed from the cache
Cache.Remove(new MyType { Id = 2 });
// After which, only 2 items are returned from the repository
// since the cache exists, it won't even try to hit the database
count = rep.GetAll().Count();
// Now count = 2, while WE know the backend has now 3 items
// how would the program detect it and get a fresh copy from backend?
#endregion
}
}
在这种情况下你会做什么?是否存在有助于检测情况并从后端获取新鲜集合的模式。什么是最佳实践?
答案 0 :(得分:1)
恕我直言,
1-如果您没有在数据库之间添加,那么您可以保留一个计数器并在启动应用程序时填充它。
2-如果您可以将List更改为可观察的集合,该集合在更新时进行更新,那么当项目被删除时,您将收到通知,您可以与计数器核实是否可以重新加载它。
3-如果无法使用可观察的集合,那么你可以使用CacheExpiray策略的概念,在这个策略中你可以模拟一段时间后会从源重新加载的缓存。
答案 1 :(得分:0)
可能有一些选择。
首先,使用到期缓存。只需为当前缓存设置特定的过期即可。如果时间已过,则刷新数据。但是,这种模式不能
if(cacheExpiry){
cacheList = GetListFromDatabase();
}
但是,如果您想确保获取最新数据,通常我会使用此方法:
1,设置生成缓存时的当前时间戳。一些例子:
DateTime lastCache = DateTime.Now
然后在你的sql中,有一个包含最新修改日期时间的表(例如UPDATE_STAMP)。然后,每次修改所需的缓存表时,请将UPDATE_STAMP表中的记录更新为当前日期。例如:
Update MyTable set //your code here
Update UPDATE_STAMP set DATE_TIME = GETDATE()
然后每次获得ListCached时,将最新的缓存时间与UPDATE_STAMP表记录进行比较。例如:
public IEnumerable<MyType> ListCached
{
get {
DateTime latestModified = GetLatestModifiedDate();
if(lastCache<latestModified) Cache = GetListFromDatabase();
latestModified = DateTime.Now;
return Cache.GetAll<MyType>();
}
}