最佳答案
对于初学者,让我直接抛出它,我知道下面的代码不是线程安全的(更正: 可能是)。我所努力的是找到一个实现,一个我可以在测试中真正失败的实现。我现在正在重构一个大型的 WCF 项目,它需要缓存一些(大多数)静态数据,并从 SQL 数据库中填充这些数据。它需要过期和“刷新”,至少每天一次,这就是为什么我使用 MemoryCache。
我知道下面的代码不应该是线程安全的,但是我不能让它在繁重的负载下失败,也不能让问题复杂化谷歌搜索显示两种方式的实现(有或没有锁结合是否有必要的争论。
在多线程环境中了解 Memory Cache 的人能否让我确切地知道我是否需要在适当的地方锁定,以便在检索/再填充过程中不会抛出要删除的调用(这个调用很少被调用,但它是一个需求)。
public class MemoryCacheService : IMemoryCacheService
{
private const string PunctuationMapCacheKey = "punctuationMaps";
private static readonly ObjectCache Cache;
private readonly IAdoNet _adoNet;
static MemoryCacheService()
{
Cache = MemoryCache.Default;
}
public MemoryCacheService(IAdoNet adoNet)
{
_adoNet = adoNet;
}
public void ClearPunctuationMaps()
{
Cache.Remove(PunctuationMapCacheKey);
}
public IEnumerable GetPunctuationMaps()
{
if (Cache.Contains(PunctuationMapCacheKey))
{
return (IEnumerable) Cache.Get(PunctuationMapCacheKey);
}
var punctuationMaps = GetPunctuationMappings();
if (punctuationMaps == null)
{
throw new ApplicationException("Unable to retrieve punctuation mappings from the database.");
}
if (punctuationMaps.Cast<IPunctuationMapDto>().Any(p => p.UntaggedValue == null || p.TaggedValue == null))
{
throw new ApplicationException("Null values detected in Untagged or Tagged punctuation mappings.");
}
// Store data in the cache
var cacheItemPolicy = new CacheItemPolicy
{
AbsoluteExpiration = DateTime.Now.AddDays(1.0)
};
Cache.AddOrGetExisting(PunctuationMapCacheKey, punctuationMaps, cacheItemPolicy);
return punctuationMaps;
}
//Go oldschool ADO.NET to break the dependency on the entity framework and need to inject the database handler to populate cache
private IEnumerable GetPunctuationMappings()
{
var table = _adoNet.ExecuteSelectCommand("SELECT [id], [TaggedValue],[UntaggedValue] FROM [dbo].[PunctuationMapper]", CommandType.Text);
if (table != null && table.Rows.Count != 0)
{
return AutoMapper.Mapper.DynamicMap<IDataReader, IEnumerable<PunctuationMapDto>>(table.CreateDataReader());
}
return null;
}
}