[英]What is the best approach for caching database queries
我正在編寫一個管理智能應用程序,該應用程序需要大量復雜的數據庫查詢,而某些查詢則非常昂貴。 為了提高性能,我大量使用Memcached在內存中存儲盡可能多的內容。
這導致了我代碼中的大量重復,我渴望擺脫這些重復並構建更干凈的數據訪問解決方案。 我的很多數據訪問功能最終都看起來像這樣。
public int NumberOfTimeouts(DateTime date, int? applicationId)
{
var functionCacheKey = "NumberOfTimeouts";
var cacheKey = string.Format("{0}-{1}-{2}-{3}", RepositoryCacheKey, functionCacheKey, date, applicationId);
var cachedNumberTimeouts = _cache.Retrieve(cacheKey);
if (cachedNumberTimeouts != null)
{
return (int)cachedNumberTimeouts;
}
//query logic here, calculates numberOfTimeouts
UpdateCache(date, cacheKey, numberOfTimeouts);
return numberOfTimeouts;
}
我只是不太確定這是什么標准方法,它可能涉及使用自定義屬性類還是類似的東西?
這是一個跨領域的問題。 Decorator
模式可能在這里適用。 我可能沒有這種模式的經驗,但是我會試一試
// model
public class CustomObject
{
public int Id { get; set; }
}
// interface
public interface IRepository<T>
{
IEnumerable<T> Find(Expression<Func<T, bool>> expression);
}
public interface ICacheableRepository<T>
{
IEnumerable<T> Find(Expression<Func<T, bool>> expression, Func<int> cacheKey);
}
public interface IRepositoryCacheManager<T>
{
IEnumerable<T> Get(int key);
bool Any(int key);
void Add(int key, IEnumerable<T> result);
}
// cache manager
public class RepositoryCacheManager<T> : IRepositoryCacheManager<T>
{
private Dictionary<int, IEnumerable<T>> cache = new Dictionary<int,IEnumerable<T>>();
#region IRepositoryCache<T> Members
public IEnumerable<T> Get(int key)
{
return cache[key];
}
public bool Any(int key)
{
IEnumerable<T> result = null;
return cache.TryGetValue(key, out result);
}
public void Add(int key, IEnumerable<T> result)
{
cache.Add(key, result);
}
#endregion
}
// cache repository decorator
public class CachedRepositoryDecorator<T> : IRepository<T>, ICacheableRepository<T>
{
public CachedRepositoryDecorator(IRepositoryCacheManager<T> cache
, IRepository<T> member)
{
this.member = member;
this.cache = cache;
}
private IRepository<T> member;
private IRepositoryCacheManager<T> cache;
#region IRepository<T> Members
// this is not caching
public IEnumerable<T> Find(Expression<Func<T, bool>> expression)
{
return member.Find(expression);
}
#endregion
#region ICacheableRepository<T> Members
public IEnumerable<T> Find(Expression<Func<T, bool>> expression, Func<int> cacheKey)
{
if (cache.Any(cacheKey()))
{
return cache.Get(cacheKey());
}
else
{
IEnumerable<T> result = member.Find(expression);
cache.Add(cacheKey(), result);
return result;
}
}
#endregion
}
// object repository
public class CustomObjectRepository : IRepository<CustomObject>
{
#region IRepository<CustomObject> Members
public IEnumerable<CustomObject> Find(Expression<Func<CustomObject, bool>> expression)
{
List<CustomObject> cust = new List<CustomObject>();
// retrieve data here
return cust;
}
#endregion
}
// example
public class Consumer
{
// this cache manager should be persistent, maybe can be used in static, etc
IRepositoryCacheManager<CustomObject> cache = new RepositoryCacheManager<CustomObject>();
public Consumer()
{
int id = 25;
ICacheableRepository<CustomObject> customObjectRepository =
new CachedRepositoryDecorator<CustomObject>(
cache
, new CustomObjectRepository()
);
customObjectRepository.Find(k => k.Id == id, () => { return id; });
}
}
請注意:
Find
的ICacheableRepository
重載而產生的代碼味道,但是我無法使用Expression
作為Dictionary
Key
優點:
SRP
缺點:
歸功於這篇文章 :)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.