为什么缓存是每位 C# 开发人员的超能力
\n想象一下:您的应用程序每次都要去数据库查询同一个城市列表或汇率。数据库是一种缓慢且昂贵的资源。如果我们告诉您,可以在 1 毫秒内而不是 100 毫秒内响应用户呢?是的,这不是魔法,而是合理的 C# 数据缓存。
\n缓存是一种将频繁请求的数据临时存储在快速存储(通常是内存)中的技术。在本文中,我们将探讨如何在 .NET 应用程序中引入缓存,既使用内置机制,也使用外部解决方案。您将学习如何正确选择策略,并避免陷入数据过时的陷阱。
\n\nC# 中的缓存类型:从 MemoryCache 到 Redis
\n在 .NET 生态系统中,有几种缓存方法。选择取决于您的应用程序架构:单体应用还是微服务,单服务器还是集群。
\n\n1. 内置 MemoryCache (System.Runtime.Caching / Microsoft.Extensions.Caching.Memory)
\n最简单、最快速的方法是使用 IMemoryCache。数据存储在进程的内存中。非常适合单线程应用程序或简单的网站。
在 ASP.NET Core 中注册和使用的示例:
\n// 在 Program.cs 中\nbuilder.Services.AddMemoryCache();\n\n// 在控制器或服务中\npublic class WeatherService\n{\n private readonly IMemoryCache _cache;\n\n public WeatherService(IMemoryCache cache)\n {\n _cache = cache;\n }\n\n public async Task<string> GetWeatherAsync(string city)\n {\n string cacheKey = $"weather_{city}";\n\n // 尝试从缓存中获取数据\n if (_cache.TryGetValue(cacheKey, out string cachedData))\n {\n return cachedData;\n }\n\n // 如果没有数据,则加载(例如,从 API)\n string weatherData = await FetchWeatherFromApi(city);\n\n // 保存到缓存,有效期 10 分钟\n var cacheEntryOptions = new MemoryCacheEntryOptions()\n .SetAbsoluteExpiration(TimeSpan.FromMinutes(10));\n\n _cache.Set(cacheKey, weatherData, cacheEntryOptions);\n\n return weatherData;\n }\n}\n关键方法:TryGetValue、Set、Remove。请注意过期策略:绝对过期时间(数据在 N 分钟后精确过期)和 滑动过期时间(数据在访问期间保持有效,并在最后一次请求后 N 分钟内有效)。
2. 分布式缓存:通过 IDistributedCache 使用 Redis
\n如果您的应用程序有多个实例(Web 场、微服务),MemoryCache 就不适用了——每个服务器都会存储自己的副本。这时 Redis 就派上用场了。它作为一个独立的服务器运行,对所有实例共享。
\n在 C# 中连接 Redis:
\n// 安装包:Microsoft.Extensions.Caching.StackExchangeRedis\nbuilder.Services.AddStackExchangeRedisCache(options =>\n{\n options.Configuration = "localhost:6379";\n options.InstanceName = "SampleInstance";\n});\n\n// 通过 IDistributedCache 使用\npublic class ProductService\n{\n private readonly IDistributedCache _cache;\n\n public ProductService(IDistributedCache cache)\n {\n _cache = cache;\n }\n\n public async Task<Product> GetProductAsync(int id)\n {\n string cacheKey = $"product_{id}";\n var cachedProduct = await _cache.GetStringAsync(cacheKey);\n\n if (cachedProduct != null)\n {\n return JsonSerializer.Deserialize<Product>(cachedProduct);\n }\n\n var product = await FetchProductFromDb(id);\n var serialized = JsonSerializer.Serialize(product);\n\n await _cache.SetStringAsync(cacheKey, serialized, new DistributedCacheEntryOptions\n {\n AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30)\n });\n\n