1. 引入 Redis 依赖
在 Water.Api 项目中安装 Redis 客户端包:右键项目 → 管理 NuGet 包 → 安装 StackExchange.Redis(主流 Redis 客户端)。
2. 配置 Redis 连接在
appsettings.json 中添加 Redis 连接字符串:
cs
{
"ConnectionStrings": {
"DefaultConnection": "数据库连接字符串",
"Redis": "localhost:6379,password=你的密码,defaultDatabase=0" // Redis 连接串 没有设置密码就删除password选项
}
}
3. 注册 Redis 服务(Program.cs)
cs
using StackExchange.Redis;
// 注册 Redis 连接
builder.Services.AddSingleton<IConnectionMultiplexer>(sp =>
{
var configuration = builder.Configuration.GetConnectionString("Redis");
return ConnectionMultiplexer.Connect(configuration);
});
4:改造业务层(添加缓存逻辑)在
WaterInfoService 中注入 Redis 并实现 "先查缓存、再查数据库、后写缓存" 的逻辑:
cs
using AutoMapper;
using StackExchange.Redis;
using System.Text.Json;
using Water.Application.Contracts.WaterInfo;
using Water.Application.Contracts.WaterInfo.Dtos;
using Water.Application.Contracts.WaterInfo.Vos;
using Water.Domain.Repositories;
using Microsoft.Extensions.Logging;
namespace Water.Application.WaterInfo.Services;
public class WaterInfoService : IWaterInfoService
{
private readonly IWaterInfoRepository _waterInfoRepository;
private readonly IMapper _mapper;
private readonly IDatabase _redisDb;
private readonly ILogger<WaterInfoService> _logger;
private const string CachePrefix = "water:info:list:";
private const int CacheExpirySeconds = 300; // 缓存过期时间(5分钟)
public WaterInfoService(
IWaterInfoRepository waterInfoRepository,
IMapper mapper,
IConnectionMultiplexer redisMultiplexer,
ILogger<WaterInfoService> logger)
{
_waterInfoRepository = waterInfoRepository;
_mapper = mapper;
_redisDb = redisMultiplexer.GetDatabase();
_logger = logger;
}
public async Task<List<WaterInfoListVo>> GetWaterInfoListAsync(WaterInfoQueryDto waterInfoQueryDto)
{
string cacheKey;
// 生成缓存键(区分"全部商品"和"按分类查询")
if (waterInfoQueryDto.CategoryId.HasValue)
{
cacheKey = $"{CachePrefix}category:{waterInfoQueryDto.CategoryId.Value}";
}
else
{
cacheKey = $"{CachePrefix}all";
}
try
{
// 尝试从 Redis 读取缓存
var cachedData = await _redisDb.StringGetAsync(cacheKey);
if (!cachedData.IsNull)
{
return JsonSerializer.Deserialize<List<WaterInfoListVo>>(cachedData)!;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Redis 查询失败,降级到数据库查询");
// 异常时继续执行数据库查询逻辑
}
// 缓存不存在,查询数据库
var domainEntities = await _waterInfoRepository.GetWaterInfoListAsync(
categoryId: waterInfoQueryDto.CategoryId,
name: waterInfoQueryDto.Name
);
var voList = _mapper.Map<List<WaterInfoListVo>>(domainEntities);
// 仅当未传"商品名称"时,才写入缓存(模糊查询不缓存)
if (string.IsNullOrEmpty(waterInfoQueryDto.Name))
{
await _redisDb.StringSetAsync(
key: cacheKey,
value: JsonSerializer.Serialize(voList),
expiry: TimeSpan.FromSeconds(CacheExpirySeconds)
);
}
return voList;
}
}
5:处理缓存失效(可选,数据更新时清理缓存)
当商品数据发生变更(新增、修改、删除)时,需主动删除对应缓存,示例(假设存在修改方法):
cs
// 在 WaterInfoService 中新增修改方法(示例)
public async Task<bool> UpdateWaterInfoAsync(WaterInfoUpdateDto updateDto)
{
// 1. 执行数据库修改逻辑(略)
var isSuccess = await _waterInfoRepository.UpdateAsync(updateDto);
// 2. 删除缓存(确保下次查询获取最新数据)
var cacheKeys = new List<string> { $"{CachePrefix}all" }; // 先删除"全部商品"缓存
if (updateDto.CategoryId.HasValue)
{
cacheKeys.Add($"{CachePrefix}category:{updateDto.CategoryId.Value}"); // 再删除"对应分类"缓存
}
foreach (var key in cacheKeys)
{
await _redisDb.KeyDeleteAsync(key);
}
return isSuccess;
}