我有一个简单的缓存机制,用于服务中的重复任务。它使用静态变量来存储信息。请建议它是如何和如果它可以更好。
前提:我需要核实商店的交易。在多个商店中可以重复发生大量的事务。因此,这个简单的缓存管理器用于获取存储信息。我希望它是简单的,但有效和快速。
public class StoreCacheManager
{
private static List<StoreCacheInformation> _merchantStores = new List<StoreCacheInformation>();
private DBEntities _db;
private TimeSpan _cacheTime = new TimeSpan(1, 0, 0);//1 Hour
public TimeSpan CacheTimeSpan { get { return _cacheTime; } }
public StoreCacheManager(DBEntities db)
{
_db = db;
}
public async Task<StoreCacheInformation> Get(int storeId)
{
if (_merchantStores.Any())
{
var store =
_merchantStores.FirstOrDefault(i => i.StoreID == storeId);
if (store != null)
{
// Check if Cache time has expired
if (store.CacheDateTimeUtc.Add(_cacheTime) < DateTime.UtcNow)
{
lock (_merchantStores)
{
_merchantStores.Remove(store);
}
}
else
{
return store;
}
}
}
return await GetAndCache(storeId);
}
private async Task<StoreCacheInformation> GetAndCache(int storeId)
{
var store = await GetStoreInfo(storeId);
if (store != null)
{
lock (_merchantStores)
{
_merchantStores.Add(store);
}
}
return store;
}
private async Task<StoreCacheInformation> GetStoreInfo(int storeId)
{
var storeInfo = await _db.Stores.Where(i => i.StoreID == storeId).Select(i => new StoreCacheInformation()
{
CountryCode = i.CountryObj.CountryCode,
MerchantID = i.VendorOrgID ?? 0,
TelephoneCode = i.CountryObj.TelephoneCountryCode,
StoreID = storeId,
//todo: deviceId and Token
}).FirstOrDefaultAsync();
if (storeInfo != null)
{
storeInfo.CacheDateTimeUtc = DateTime.UtcNow;
}
return storeInfo;
}
}
public class StoreCacheInformation
{
public int MerchantID { get; set; }
public int StoreID { get; set; }
public string TelephoneCode { get; set; }
public string CountryCode { get; set; }
public DateTime CacheDateTimeUtc { get; set; }
public string DeviceId { get; set; }
public string AuthToken { get; set; }
}
发布于 2016-07-11 09:38:57
如果要实现线程安全,还必须锁定整个事务。例如:store != null
假定缓存中没有项。想象一下,在检查之后,另一个线程添加了一个线程。这将导致缓存,其中相同的项目被缓存两次。
考虑使用线程安全集合(例如,ConcurrentDictionary而不是使用锁定)。
.Net框架已经提供了一个线程安全缓存:MemoryCacheMemoryCache。
我不太熟悉实体框架,但据我所知是DbContext非线程安全。因此,在多线程环境中使用它的单个实例并不是一个好主意。
_merchantStores
、_db
和_cacheTime
应该是只读的.Task
的方法应该称为xxxAsyncStoreCacheInformation
中的属性设置程序应该是私有的,或者至少是内部的。其他视图外部代码可以修改缓存项的状态。发布于 2016-07-11 11:06:03
更新
StoreCacheManager.cs
public class StoreCacheManager
{
//private static List<StoreCacheInformation> _merchantStores = new List<StoreCacheInformation>();
private static readonly ConcurrentDictionary<int, StoreCacheInformation> _merchantStores =
new ConcurrentDictionary<int, StoreCacheInformation>();
private readonly DBEntities _db;
private readonly TimeSpan _cacheTime = new TimeSpan(1, 0, 0);//1 Hour
public TimeSpan CacheTimeSpan { get { return _cacheTime; } }
public StoreCacheManager(DBEntities db)
{
_db = db;
var x = new System.Web.Caching.Cache();
}
public StoreCacheInformation Get(int storeId)
{
lock (_merchantStores)
{
if (_merchantStores.Any())
{
var store =
_merchantStores.FirstOrDefault(i => i.Key == storeId);
if (store.Value != null)
{
// Check if Cache time has expired
if (store.Value.CacheDateTimeUtc.Add(_cacheTime) < DateTime.UtcNow)
{
_merchantStores.Remove(storeId);
}
else
{
return store.Value;
}
}
}
return GetAndCache(storeId);
}
}
private StoreCacheInformation GetAndCache(int storeId)
{
var store = GetStoreInfo(storeId);
if (store != null)
{
_merchantStores.TryAdd(storeId, store);
}
return store;
}
private StoreCacheInformation GetStoreInfo(int storeId)
{
var storeInfo = _db.Stores.Where(i => i.StoreID == storeId).Select(i => new StoreCacheInformation()
{
CountryCode = i.CountryObj.CountryCode,
MerchantID = i.VendorOrgID ?? 0,
TelephoneCode = i.CountryObj.TelephoneCountryCode,
StoreID = storeId,
//todo: deviceId and Token
}).FirstOrDefault();
if (storeInfo != null)
{
storeInfo.CacheDateTimeUtc = DateTime.UtcNow;
}
return storeInfo;
}
}
变化
https://codereview.stackexchange.com/questions/134518
复制相似问题