YD_Event.Admin/YD_Event.Core/Domain/OrderNoGeneratorService.cs

122 lines
3.7 KiB
C#
Raw Normal View History

2026-04-10 22:39:32 +08:00
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Microsoft.Extensions.Logging;
using SqlSugar;
using YD_Event.Core.Entities;
namespace YD_Event.Core.Domain;
/// <summary>
/// 订单号生成器服务
/// 提供分布式唯一订单号生成,确保高并发下的唯一性
/// </summary>
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<EventRegistration> _registrationRepository;
private readonly ILogger<OrderNoGeneratorService> _logger;
public OrderNoGeneratorService(
ISqlSugarRepository<EventRegistration> registrationRepository,
ILogger<OrderNoGeneratorService> logger)
{
_registrationRepository = registrationRepository;
_logger = logger;
}
/// <summary>
/// 生成唯一订单号
/// 格式:yyyyMMddHHmmss + 4位序列号
/// 保证高并发下的唯一性
/// </summary>
/// <returns>唯一订单号</returns>
public async Task<string> 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("订单号生成失败,请稍后重试");
}
/// <summary>
/// 生成退款订单号
/// 格式:REF + yyyyMMddHHmmss + 4位序列号
/// </summary>
/// <returns>退款订单号</returns>
public async Task<string> GenerateRefundOrderNoAsync()
{
var baseOrderNo = await GenerateOrderNoAsync();
return "REF" + baseOrderNo;
}
/// <summary>
/// 内部生成订单号(带线程安全的序列号)
/// </summary>
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");
}
}
/// <summary>
/// 获取时间戳(用于比较)
/// </summary>
private static long GetTimestamp(DateTime dateTime)
{
return new DateTimeOffset(dateTime).ToUnixTimeMilliseconds();
}
}