fix: 每次写入创建新 SqlSugarClient 实例
根因分析: - MarketDataRepository 使用注入的 ISqlSugarClient(Scoped) - 多个 Task.Run 并发调用 SavePriceCacheAsync - Storageable 操作使用同一个 SqlSugarScope 实例 - 连接在 await 边界被复用 → 冲突 正确方案: - SavePriceCacheAsync 每次创建新的 SqlSugarClient 实例 - MySQL 连接池会复用底层 TCP 连接,性能开销很小 - 不再需要 SemaphoreSlim 锁 优点: - 完全避免连接冲突 - 代码更简洁 - 并发写入无限制
This commit is contained in:
parent
39808c6d5d
commit
cbe0ac9f4a
@ -54,7 +54,11 @@ public class MarketDataRepository : IMarketDataRepository
|
||||
public async Task<bool> SavePriceCacheAsync(MarketPriceCache cache)
|
||||
{
|
||||
cache.Id = GenerateCacheKey(cache.Symbol, cache.AssetType);
|
||||
var result = await _db.Storageable(cache).ExecuteCommandAsync();
|
||||
|
||||
// 使用新的 SqlSugarClient 实例,避免并发写入时连接冲突
|
||||
// 连接池会复用底层连接,性能开销很小
|
||||
using var db = SqlSugarConfig.GetSqlSugarClient();
|
||||
var result = await db.Storageable(cache).ExecuteCommandAsync();
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
|
||||
@ -22,14 +22,11 @@ public class MarketDataService : IMarketDataService
|
||||
private readonly IOkxMarketService _okxService;
|
||||
private readonly IMarketDataRepository _marketDataRepo;
|
||||
|
||||
// 静态内存缓存层(跨请求共享,避免并发数据库查询导致连接池冲突)
|
||||
// 静态内存缓存层(跨请求共享)
|
||||
private static readonly ConcurrentDictionary<string, (MarketPriceCache cache, DateTime expireAt)> _memoryCache = new();
|
||||
|
||||
// 静态 pending 请求字典(跨请求共享,防止并发请求同一股票)
|
||||
private static readonly ConcurrentDictionary<string, Lazy<Task<MarketPriceResponse>>> _pendingPriceRequests = new();
|
||||
|
||||
// 静态写入锁(串行化数据库写入)
|
||||
private static readonly SemaphoreSlim _writeLock = new(1, 1);
|
||||
|
||||
public MarketDataService(
|
||||
ILogger<MarketDataService> logger,
|
||||
@ -203,10 +200,10 @@ public class MarketDataService : IMarketDataService
|
||||
ExpiredAt = expireAt
|
||||
}, expireAt);
|
||||
|
||||
// 写入数据库缓存(串行化,避免连接冲突)
|
||||
// 写入数据库缓存(后台执行,失败不影响主流程)
|
||||
// SavePriceCacheAsync 每次创建新的 SqlSugarClient 实例,避免连接冲突
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await _writeLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
await SavePriceCacheAsync(symbol, assetType, response, source);
|
||||
@ -215,10 +212,6 @@ public class MarketDataService : IMarketDataService
|
||||
{
|
||||
_logger.LogWarning(ex, "[数据库缓存写入失败] Symbol={Symbol},忽略(内存缓存已生效)", symbol);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_writeLock.Release();
|
||||
}
|
||||
});
|
||||
|
||||
return response;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user