diff --git a/AssetManager.Data/DatabaseExtensions.cs b/AssetManager.Data/DatabaseExtensions.cs index 27e969d..76efdb2 100755 --- a/AssetManager.Data/DatabaseExtensions.cs +++ b/AssetManager.Data/DatabaseExtensions.cs @@ -8,7 +8,9 @@ public static class DatabaseExtensions { public static IServiceCollection AddDatabase(this IServiceCollection services) { - services.AddScoped(s => + // 使用 Singleton 注册 SqlSugarScope(线程安全,内部使用 AsyncLocal) + // SqlSugarScope 设计上支持并发,会自动管理连接池 + services.AddSingleton(s => { return SqlSugarConfig.GetSqlSugarClient(); }); diff --git a/AssetManager.Infrastructure/Services/MarketDataService.cs b/AssetManager.Infrastructure/Services/MarketDataService.cs index a3427f4..d5e5206 100755 --- a/AssetManager.Infrastructure/Services/MarketDataService.cs +++ b/AssetManager.Infrastructure/Services/MarketDataService.cs @@ -20,9 +20,6 @@ public class MarketDataService : IMarketDataService private readonly ITiingoMarketService _tiingoService; private readonly IOkxMarketService _okxService; private readonly IMarketDataRepository _marketDataRepo; - - // 限制数据库并发访问,避免 SqlSugar 连接状态冲突 - private static readonly SemaphoreSlim _dbSemaphore = new(3, 3); public MarketDataService( ILogger logger, @@ -47,29 +44,20 @@ public class MarketDataService : IMarketDataService { _logger.LogInformation("获取实时价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType); - // 限制数据库并发访问 - await _dbSemaphore.WaitAsync(); - try - { - // 先查缓存 - var cached = await _marketDataRepo.GetPriceCacheAsync(symbol, assetType); + // 先查缓存 + var cached = await _marketDataRepo.GetPriceCacheAsync(symbol, assetType); - if (cached != null) - { - _logger.LogDebug("缓存命中: {Symbol} {AssetType}, 价格: {Price}", symbol, assetType, cached.Price); - return new MarketPriceResponse - { - Symbol = cached.Symbol, - Price = cached.Price, - PreviousClose = cached.PreviousClose ?? 0, - Timestamp = cached.FetchedAt, - AssetType = cached.AssetType - }; - } - } - finally + if (cached != null) { - _dbSemaphore.Release(); + _logger.LogDebug("缓存命中: {Symbol} {AssetType}, 价格: {Price}", symbol, assetType, cached.Price); + return new MarketPriceResponse + { + Symbol = cached.Symbol, + Price = cached.Price, + PreviousClose = cached.PreviousClose ?? 0, + Timestamp = cached.FetchedAt, + AssetType = cached.AssetType + }; } // 缓存未命中,调用API @@ -120,17 +108,8 @@ public class MarketDataService : IMarketDataService _logger.LogInformation("获取历史数据: {Symbol}, 资产类型: {AssetType}, 周期: {Timeframe}, 数量: {Limit}", symbol, assetType, timeframe, limit); - // 限制数据库并发访问 - await _dbSemaphore.WaitAsync(); - List cachedKlines; - try - { - cachedKlines = await _marketDataRepo.GetKlineCacheAsync(symbol, assetType, timeframe, limit); - } - finally - { - _dbSemaphore.Release(); - } + // 先查缓存 + var cachedKlines = await _marketDataRepo.GetKlineCacheAsync(symbol, assetType, timeframe, limit); // 缓存足够,直接返回 if (cachedKlines.Count >= limit) @@ -235,15 +214,7 @@ public class MarketDataService : IMarketDataService ExpiredAt = GetCacheExpirationTime(assetType) }; - await _dbSemaphore.WaitAsync(); - try - { - await _marketDataRepo.SavePriceCacheAsync(cacheEntity); - } - finally - { - _dbSemaphore.Release(); - } + await _marketDataRepo.SavePriceCacheAsync(cacheEntity); _logger.LogDebug("缓存写入: {Symbol} {AssetType}, 过期时间: {ExpiredAt}", symbol, assetType, cacheEntity.ExpiredAt); } @@ -264,15 +235,7 @@ public class MarketDataService : IMarketDataService FetchedAt = DateTime.Now }).ToList(); - await _dbSemaphore.WaitAsync(); - try - { - await _marketDataRepo.SaveKlineCacheBatchAsync(cacheEntities); - } - finally - { - _dbSemaphore.Release(); - } + await _marketDataRepo.SaveKlineCacheBatchAsync(cacheEntities); _logger.LogDebug("历史K线缓存写入: {Symbol} {AssetType} {Timeframe}, 数量: {Count}", symbol, assetType, timeframe, cacheEntities.Count); }