SQL Server(关系型数据库)与 Redis(缓存 / 高性能存储)
SQL Server 做 “存储”:存核心数据、支持复杂查询(JOIN、事务等)。Redis 做 “加速” 和 “扩展”:缓存高频读数据、处理高并发计数 / 排序场景、存储临时会话等。通过这种分工,既能保证数据的持久性和一致性(依赖 SQL Server),又能提升系统的读写性能和并发能力(依赖 Redis),是互联网项目的经典架构模式。
SQL Server 负责存储核心业务数据(保证持久性和复杂查询能力),Redis 负责缓存高频访问数据(提升读取性能)或处理特定场景(如计数器、排行榜)。
一、核心结合模式:缓存加速查询
这是最常见的场景:用 Redis 缓存 SQL Server 中查询频繁但修改较少的数据(如商品信息、用户基本信息),减少 SQL Server 的查询压力。
实现流程:
- 查询数据时:先查 Redis → 命中则直接返回;未命中则查 SQL Server,同时将结果存入 Redis。
- 更新数据时:先更新 SQL Server → 再更新或删除 Redis 中的缓存(保证数据一致性)。
代码示例(.NET):
// 假设这是操作 SQL Server 的仓储类
public class SqlUserRepository
{
private readonly DbContext _dbContext; // EF Core 上下文
public async Task<User?> GetByIdAsync(int id)
{
return await _dbContext.Users.FindAsync(id);
}
public async Task UpdateAsync(User user)
{
_dbContext.Users.Update(user);
await _dbContext.SaveChangesAsync();
}
}
// 结合 Redis 的业务服务
public class UserService
{
private readonly SqlUserRepository _sqlRepo; // SQL Server 操作
private readonly ICacheRepository _redisCache; // Redis 缓存(封装后的接口)
public UserService(SqlUserRepository sqlRepo, ICacheRepository redisCache)
{
_sqlRepo = sqlRepo;
_redisCache = redisCache;
}
// 1. 查询用户(先查缓存,再查数据库)
public async Task<User?> GetUserAsync(int userId)
{
var cacheKey = $"user:{userId}";
// 步骤1:查 Redis 缓存
var cachedUser = await _redisCache.GetAsync<User>(cacheKey);
if (cachedUser != null)
{
Console.WriteLine("从 Redis 缓存获取数据");
return cachedUser;
}
// 步骤2:缓存未命中,查 SQL Server
var user = await _sqlRepo.GetByIdAsync(userId);
if (user != null)
{
// 步骤3:将数据库结果存入 Redis(设置1小时过期)
await _redisCache.SetAsync(cacheKey, user, TimeSpan.FromHours(1));
Console.WriteLine("从 SQL Server 获取数据,并更新到 Redis");
}
return user;
}
// 2. 更新用户(先更数据库,再更缓存)
public async Task UpdateUserAsync(User user)
{
// 步骤1:先更新 SQL Server
await _sqlRepo.UpdateAsync(user);
// 步骤2:更新或删除 Redis 缓存(避免缓存与数据库不一致)
var cacheKey = $"user:{user.Id}";
await _redisCache.DeleteAsync(cacheKey); // 简单处理:直接删除旧缓存
// 或更优:更新缓存为新值
// await _redisCache.SetAsync(cacheKey, user, TimeSpan.FromHours(1));
}
}
其他结合场景
1. 计数器场景(Redis 擅长,减轻 SQL 压力)
例如文章阅读量:用 Redis 的 INCR 实时累加,定期同步到 SQL Server 持久化。
csharp
// 1. 每次访问文章,用 Redis 计数(高效,支持高并发)
public async Task IncreaseReadCountAsync(int articleId)
{
var countKey = $"article:read:{articleId}";
await _redisCache.StringIncrementAsync(countKey); // Redis 原子自增
}
// 2. 定时任务(如每小时)将 Redis 计数同步到 SQL Server
public async Task SyncReadCountToSqlAsync()
{
// 从 Redis 批量获取计数
var articleIds = new List<int> { 1001, 1002, 1003 }; // 实际可通过扫描获取所有键
foreach (var id in articleIds)
{
var countKey = $"article:read:{id}";
var count = await _redisCache.StringGetAsync<long>(countKey);
if (count > 0)
{
// 更新到 SQL Server(如累加至 Article 表的 ReadCount 字段)
await _sqlRepo.IncreaseReadCountAsync(id, count);
// 重置 Redis 计数(或保留用于下一次累加)
await _redisCache.DeleteAsync(countKey);
}
}
}
2. 会话存储(替代 SQL Server 的 Session 表)
传统 ASP.NET 会话可能存在 SQL Server 中,高并发时性能差。可改用 Redis 存储会话:
- 安装 NuGet 包:
Microsoft.AspNetCore.Session+Microsoft.Extensions.Caching.StackExchangeRedis - 配置 Startup(.NET 6+ 为 Program.cs):
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(30);
});
// 使用 Redis 存储会话
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
options.InstanceName = "session:"; // 会话键前缀
});
// 中间件启用会话
app.UseSession();
- 使用方式不变,但会话数据实际存在 Redis 中,性能远高于 SQL Server。
3. 热点数据临时存储(Redis 抗高并发)
例如秒杀活动的库存:用 Redis 的 DECR 预减库存(防止超卖),最终库存变更同步到 SQL Server。
// 1. 秒杀时先查 Redis 库存(高并发下性能好)
public async Task<bool> SeckillAsync(int productId)
{
var stockKey = $"seckill:stock:{productId}";
// 预减库存(原子操作,防止超卖)
var remaining = await _redisCache.StringDecrementAsync(stockKey);
if (remaining < 0)
{
// 库存不足,恢复计数
await _redisCache.StringIncrementAsync(stockKey);
return false;
}
// 2. 库存充足,记录订单(异步同步到 SQL Server)
await _sqlRepo.CreateOrderAsync(productId);
return true;
}
// 初始化:活动开始前从 SQL Server 加载库存到 Redis
public async Task InitSeckillStockAsync(int productId)
{
var stock = await _sqlRepo.GetProductStockAsync(productId);
await _redisCache.StringSetAsync($"seckill:stock:{productId}", stock);
}
三、数据一致性保障
SQL Server 与 Redis 结合的核心挑战是数据一致性,需根据业务场景选择策略:
-
Cache-Aside 模式(最常用):
- 读:先查缓存 → 未命中查数据库并更新缓存
- 写:先更数据库 → 再删缓存(避免旧缓存残留)
-
过期时间兜底:
给 Redis 缓存设置合理的过期时间(如 1 小时),即使缓存与数据库短暂不一致,过期后也会自动更新。 -
分布式锁(强一致性场景):
对并发写场景(如库存),用 Redis 分布式锁保证同一时间只有一个线程更新数据。
四、总结
SQL Server 与 Redis 结合的核心思路是:
- SQL Server 做 “存储”:存核心数据、支持复杂查询(JOIN、事务等)。
- Redis 做 “加速” 和 “扩展”:缓存高频读数据、处理高并发计数 / 排序场景、存储临时会话等。
通过这种分工,既能保证数据的持久性和一致性(依赖 SQL Server),又能提升系统的读写性能和并发能力(依赖 Redis),是互联网项目的经典架构模式。
![]()
二、其他结合场景
更多推荐
所有评论(0)