首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >简单缓存机制

简单缓存机制
EN

Code Review用户
提问于 2016-07-11 09:16:20
回答 2查看 1.1K关注 0票数 6

我有一个简单的缓存机制,用于服务中的重复任务。它使用静态变量来存储信息。请建议它是如何和如果它可以更好。

前提:我需要核实商店的交易。在多个商店中可以重复发生大量的事务。因此,这个简单的缓存管理器用于获取存储信息。我希望它是简单的,但有效和快速。

StoreCacheManager.cs

代码语言:javascript
运行
复制
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;
    }
}

StoreCacheInformation.cs

代码语言:javascript
运行
复制
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; }
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2016-07-11 09:38:57

并发

如果要实现线程安全,还必须锁定整个事务。例如:store != null假定缓存中没有项。想象一下,在检查之后,另一个线程添加了一个线程。这将导致缓存,其中相同的项目被缓存两次。

考虑使用线程安全集合(例如,ConcurrentDictionary而不是使用锁定)。

.Net框架已经提供了一个线程安全缓存:MemoryCacheMemoryCache

我不太熟悉实体框架,但据我所知是DbContext非线程安全。因此,在多线程环境中使用它的单个实例并不是一个好主意。

码样式

  • _merchantStores_db_cacheTime应该是只读的.
  • 返回Task的方法应该称为xxxAsync
  • StoreCacheInformation中的属性设置程序应该是私有的,或者至少是内部的。其他视图外部代码可以修改缓存项的状态。
  • 对于许多缓存的项,最好使用字典而不是列表。
票数 6
EN

Code Review用户

发布于 2016-07-11 11:06:03

更新

StoreCacheManager.cs

代码语言:javascript
运行
复制
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;
    }
}

变化

  • 增加了整个事务的锁。异步任务必须执行,因为它会产生诸如“等待”之类的错误,不能与try...catch一起使用,锁定
  • 使属性成为只读的。
  • 添加扩展以删除方法
票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/134518

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档