using Furion.DependencyInjection; using Furion.FriendlyException; using Microsoft.Extensions.Logging; using SqlSugar; using YD_Event.Core.Entities; namespace YD_Event.Core.Domain; /// /// 订单号生成器服务 /// 提供分布式唯一订单号生成,确保高并发下的唯一性 /// public class OrderNoGeneratorService : ITransient { private static readonly object _lock = new(); private static long _lastTimestamp = -1; private static int _sequence = 0; private const int MaxSequence = 9999; private readonly ISqlSugarRepository _registrationRepository; private readonly ILogger _logger; public OrderNoGeneratorService( ISqlSugarRepository registrationRepository, ILogger logger) { _registrationRepository = registrationRepository; _logger = logger; } /// /// 生成唯一订单号 /// 格式:yyyyMMddHHmmss + 4位序列号 /// 保证高并发下的唯一性 /// /// 唯一订单号 public async Task GenerateOrderNoAsync() { string orderNo; int retryCount = 0; const int maxRetry = 5; do { orderNo = GenerateOrderNoInternal(); retryCount++; // 检查数据库中是否已存在 var exists = await _registrationRepository.IsAnyAsync(r => r.OrderNo == orderNo); if (!exists) { _logger.LogDebug("生成订单号成功: {OrderNo}", orderNo); return orderNo; } _logger.LogWarning("订单号冲突,重试中 ({RetryCount}/{MaxRetry}): {OrderNo}", retryCount, maxRetry, orderNo); // 短暂延迟后重试 await Task.Delay(10); } while (retryCount < maxRetry); _logger.LogError("订单号生成失败,已达到最大重试次数: {MaxRetry}", maxRetry); throw Oops.Bah("订单号生成失败,请稍后重试"); } /// /// 生成退款订单号 /// 格式:REF + yyyyMMddHHmmss + 4位序列号 /// /// 退款订单号 public async Task GenerateRefundOrderNoAsync() { var baseOrderNo = await GenerateOrderNoAsync(); return "REF" + baseOrderNo; } /// /// 内部生成订单号(带线程安全的序列号) /// private string GenerateOrderNoInternal() { lock (_lock) { var timestamp = DateTime.Now; var currentTimestamp = GetTimestamp(timestamp); // 如果是同一毫秒,增加序列号 if (currentTimestamp == _lastTimestamp) { _sequence++; if (_sequence > MaxSequence) { // 序列号溢出,等待下一毫秒 Thread.Sleep(1); timestamp = DateTime.Now; currentTimestamp = GetTimestamp(timestamp); _sequence = 0; } } else { // 不同毫秒,重置序列号 _sequence = 0; } _lastTimestamp = currentTimestamp; // 格式:yyyyMMddHHmmss + 4位序列号(补零) return timestamp.ToString("yyyyMMddHHmmss") + _sequence.ToString("D4"); } } /// /// 获取时间戳(用于比较) /// private static long GetTimestamp(DateTime dateTime) { return new DateTimeOffset(dateTime).ToUnixTimeMilliseconds(); } }