C# Redis是本地缓存的可行解决方案吗?
在我的场景中,我有一个连接到WebApi2的Winforms客户端。数据存储在SQL Server数据库中 为了提高性能,我正在研究在本地缓存中存储数据是否是可行的解决方案。最好,本地缓存应该存储在文件中,而不是保存在内存中,因为RAM可能是一个问题。数据都是POCO类,有些类比其他类复杂得多,大多数类都是相互关联的 我列出了哪些框架可能可行的短名单:C# Redis是本地缓存的可行解决方案吗?,c#,winforms,caching,asp.net-web-api,redis,C#,Winforms,Caching,Asp.net Web Api,Redis,在我的场景中,我有一个连接到WebApi2的Winforms客户端。数据存储在SQL Server数据库中 为了提高性能,我正在研究在本地缓存中存储数据是否是可行的解决方案。最好,本地缓存应该存储在文件中,而不是保存在内存中,因为RAM可能是一个问题。数据都是POCO类,有些类比其他类复杂得多,大多数类都是相互关联的 我列出了哪些框架可能可行的短名单: 记忆卡 MemCached 缓存管理器 StackExchange.Redis 本地数据库 使用MemoryCache,我需要实现自己的解决方案
MemoryCache
,我需要实现自己的解决方案,但它将满足我最初的需求
然而,我看到的一个常见问题是相关类的更新。例如,我在CustomerAddress
和PostCode
之间有一种关系。如果我更改postcode对象中的某些属性,我可以轻松地更新其本地缓存。但是,在本例中,CustomerAddress
,如何更新/使使用此邮政编码的任何其他类无效
上面的任何一个框架都有在这种情况下有帮助的方法吗,还是完全依赖于开发人员来处理这种缓存失效
为了提高性能,我正在研究是否在本地存储数据
缓存是一个可行的解决方案。优选地,本地缓存应该是
存储在文件中而不是作为RAM保存在内存中可能是一个问题
整个问题是避免将其存储在文件中,避免磁盘操作太慢,因此Redis是基于RAM的内存
上面的任何一个框架都有这种帮助的方法吗
情况的不同,还是完全取决于开发人员来处理
这样的缓存失效
您可以将整个对象保存为JSON,而不是应用逻辑并反汇编对象,这在应用更改时也会很慢且容易出错。该库提供了一种将标记与键和哈希关联的机制,这样您就可以在一次操作中使它们失效
我假设你会:
- 使用“Address:{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; }
}
我的建议是:
- 在Redis上用类似“Tag PostCode:{PostCodeId}”的标记标记客户地址对象
- 使用从缓存/数据库检索客户地址和邮政编码
- 更改邮政编码时,按标记使缓存对象无效
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) });
}
}
如果相关对象发生更改,会发生什么情况?与之相关的对象是否也会被更新?不,它只是一个内存容器,没有双向绑定,这是您处理更新Redis的内容和时间的部分。计算机科学中只有两个难题:缓存失效和命名PhilKarlton库(SE.Redis的包装器)可以使用简单的标记机制使键和散列无效。还有@thepirat000是一个使用这些功能的例子,我可以遵循吗?