YD_Event.Admin/YD_Event.Core/Domain/OrderNoGeneratorService.cs
2026-04-10 22:39:32 +08:00

122 lines
3.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
}
}