Web API中IDistributedCache异步Get方法缓存实现求助
实现分布式缓存逻辑的方案
咱们可以按照「先读缓存,缓存未命中再查数据库并写入缓存」的经典逻辑来实现,结合IDistributedCache的异步方法完成改造。下面是具体的代码和细节说明:
完整改造后的代码
using System.Text; using System.Text.Json; public class SvcBooking { private readonly DbContextSMATA _ctx; private readonly IMapper _mapper; private readonly IDistributedCache _cache; // 定义专属缓存键,建议加业务前缀避免键冲突 private const string _allBookingsCacheKey = "BusinessPrefix_AllBookings"; public SvcBooking(DbContextSMATA ctx, IMapper mapper, IDistributedCache cache) { _ctx = ctx; _mapper = mapper; _cache = cache; } public async Task<IList<IDtoBooking>> GetAll() { // 1. 先尝试从分布式缓存获取数据 var cachedBookingsJson = await _cache.GetStringAsync(_allBookingsCacheKey); if (!string.IsNullOrEmpty(cachedBookingsJson)) { // 缓存命中:反序列化为实体列表,再映射成DTO返回 var cachedBookings = JsonSerializer.Deserialize<IList<Booking>>(cachedBookingsJson); return _mapper.Map<IList<IDtoBooking>>(cachedBookings); } // 2. 缓存未命中:查询数据库获取最新数据 var dbBookings = await _ctx.Set<Booking>().ToListAsync(); // 3. 将数据库结果序列化后写入缓存,同时设置过期策略 var bookingsJson = JsonSerializer.Serialize(dbBookings); var cacheOptions = new DistributedCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromMinutes(30)); // 滑动过期:30分钟无访问则自动失效 await _cache.SetStringAsync(_allBookingsCacheKey, bookingsJson, cacheOptions); // 4. 映射为DTO返回给调用方 return _mapper.Map<IList<IDtoBooking>>(dbBookings); } }
关键细节提醒
- 缓存键命名:用固定的常量标识缓存项,加上业务前缀能避免和其他模块的缓存键冲突。
- 序列化方案:示例用了.NET内置的
System.Text.Json,如果项目用的是Newtonsoft.Json,替换对应的序列化/反序列化方法即可(记得安装对应NuGet包)。 - 过期策略:这里用了滑动过期,适合访问频率不稳定的场景;如果需要固定过期时间,可以用
SetAbsoluteExpiration(TimeSpan.FromHours(2)),也可以同时设置两种过期策略(以先触发的为准)。 - 异常降级(可选):如果担心缓存服务故障影响业务,可以给缓存操作套个try-catch,当缓存读写失败时直接走数据库逻辑,同时记录异常日志:
try { var cachedBookingsJson = await _cache.GetStringAsync(_allBookingsCacheKey); // ... 缓存命中逻辑 } catch (Exception ex) { // 日志记录示例,需要注入ILogger _logger.LogError(ex, "读取预订缓存失败,将直接查询数据库"); } - 缓存失效机制:当预订数据有增删改操作时,记得调用
await _cache.RemoveAsync(_allBookingsCacheKey);清空旧缓存,避免返回过时数据。
内容的提问来源于stack exchange,提问作者Gani Lastra
相关产品推荐
相关产品推荐

