在我的场景中,我有一个连接到 WebApi2 的 Winforms 客户端。数据存储在 SQL Server 数据库中。
为了提高性能,我正在研究将数据存储在本地缓存中是否是一种可行的解决方案。本地缓存最好存储在文件中,而不是保存在内存中,因为 RAM 可能是个问题。数据都是 POCO 类,有些比其他类复杂得多,并且大多数类彼此相关。
我列出了可能可行的框架:
- 内存缓存
- 内存缓存
- 缓存管理器
- StackExchange.Redis
- 本地数据库
使用 MemoryCache
,我需要实现我自己的解决方案,但它会满足我的初始要求。
但是,我看到的一个常见问题是相关类的更新。例如,我在 CustomerAddress
和 PostCode
之间有一个关系。如果我更改邮政编码对象中的某些属性,我可以轻松更新其本地缓存。但是,如何更新/使使用此邮政编码的任何其他类(在本例中为 CustomerAddress
)变得无效?
上述任何框架是否有帮助处理这种情况的方法,还是完全依赖于开发人员来处理此类缓存失效?
最佳答案
CachingFramework.Redis库提供了一种将标签与键和散列相关联的机制,因此您可以在单个操作中使它们无效。
我假设你会:
- 使用“地址:{AddressId}”等键将客户地址存储在 Redis 中。
- 使用“PostCode:{PostCodeId}”等键将邮政编码存储在 Redis 中。
你的模型是这样的:
public class CustomerAddress
{
public int CustomerAddressId { get; set; }
public int CustomerId { get; set; }
public int PostCodeId { get; set; }
}
public class PostCode
{
public int PostCodeId { get; set; }
public string Code { get; set; }
}
我的建议是:
- 使用“Tag-PostCode:{PostCodeId}”等标签在 Redis 上标记客户地址对象。
- 使用 cache-aside pattern从缓存/数据库中检索客户地址和邮政编码。
- 更改邮政编码时通过标签使缓存对象无效。
像这样的东西应该可以工作:
public class DataAccess
{
private Context _cacheContext = new CachingFramework.Redis.Context("localhost:6379");
private string FormatPostCodeKey(int postCodeId)
{
return string.Format("PostCode:{0}", postCodeId);
}
private string FormatPostCodeTag(int postCodeId)
{
return string.Format("Tag-PostCode:{0}", postCodeId);
}
private string FormatAddressKey(int customerAddressId)
{
return string.Format("Address:{0}", customerAddressId);
}
public void InsertPostCode(PostCode postCode)
{
Sql.InsertPostCode(postCode);
}
public void UpdatePostCode(PostCode postCode)
{
Sql.UpdatePostCode(postCode);
//Invalidate cache: remove CustomerAddresses and PostCode related
_cacheContext.Cache.InvalidateKeysByTag(FormatPostCodeTag(postCode.PostCodeId));
}
public void DeletePostCode(int postCodeId)
{
Sql.DeletePostCode(postCodeId);
_cacheContext.Cache.InvalidateKeysByTag(FormatPostCodeTag(postCodeId));
}
public PostCode GetPostCode(int postCodeId)
{
// Get/Insert the postcode from/into Cache with key = PostCode{PostCodeId}.
// Mark the object with tag = Tag-PostCode:{PostCodeId}
return _cacheContext.Cache.FetchObject(
FormatPostCodeKey(postCodeId), // Redis Key to use
() => Sql.GetPostCode(postCodeId), // Delegate to get the value from database
new[] { FormatPostCodeTag(postCodeId) }); // Tags related
}
public void InsertCustomerAddress(CustomerAddress customerAddress)
{
Sql.InsertCustomerAddress(customerAddress);
}
public void UpdateCustomerAddress(CustomerAddress customerAddress)
{
var updated = Sql.UpdateCustomerAddress(customerAddress);
if (updated.PostCodeId != customerAddress.PostCodeId)
{
var addressKey = FormatAddressKey(customerAddress.CustomerAddressId);
_cacheContext.Cache.RenameTagForKey(addressKey, FormatPostCodeTag(customerAddress.PostCodeId), FormatPostCodeTag(updated.PostCodeId));
}
}
public void DeleteCustomerAddress(CustomerAddress customerAddress)
{
Sql.DeleteCustomerAddress(customerAddress.CustomerAddressId);
//Clean-up, remove the postcode tag from the CustomerAddress:
_cacheContext.Cache.RemoveTagsFromKey(FormatAddressKey(customerAddress.CustomerAddressId), new [] { FormatPostCodeTag(customerAddress.PostCodeId) });
}
public CustomerAddress GetCustomerAddress(int customerAddressId)
{
// Get/Insert the address from/into Cache with key = Address:{CustomerAddressId}.
// Mark the object with tag = Tag-PostCode:{PostCodeId}
return _cacheContext.Cache.FetchObject(
FormatAddressKey(customerAddressId),
() => Sql.GetCustomerAddress(customerAddressId),
a => new[] { FormatPostCodeTag(a.PostCodeId) });
}
}
关于c# - Redis 是本地缓存的可行解决方案吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36655913/