.net 同一时间戳下生成不重复的订单标识

为了避免在业务中出现订单号重复的情况,这里针对生产订单号的方法做了一定优化,基本可以避免同一时间戳下生成重复标识的问题。

思路: 假设订单编号由 平台标识(4位)+ 年份(4位) + 时间戳(10位) +  随机数(4位)组成的22位订单编号,由于前面8位固定的,

如果我们想要避免重复,就要避免 同一时间戳下生成重复的随机数。

代码如下

复制代码
        private static readonly object _lock = new object();
        private static Dictionary<string, List<int>> _dic = new Dictionary<string, List<int>>();
        private static long _num;
        /// <summary>
        /// 生成唯一平台订单号
        /// </summary>
        /// <param name="ctype"></param>
        /// <returns></returns>
        public static string GeneratOrderNo(ContractType ctype)
        {
            lock (_lock)
            {
                TimeSpan timespan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                string timeStamp = Convert.ToInt64(timespan.TotalSeconds).ToString();

                //若时间戳 + 随机数重复, 重新生成随机数
                string nonce = GenerateNonce(timeStamp);
                return ((int)ctype).ToString() + DateTime.Now.ToString("yyyy") + timeStamp + nonce;
            }
        }

        /// <summary>
        /// 生成不重复的四位随机数(同一时间戳下不允许重复)
        /// </summary>
        /// <param name="timeStamp">10位时间戳</param>
        /// <returns></returns>
        private static string GenerateNonce(string timeStamp)
        {
            Random random = new Random(RandomHelper.GetRandomSeed());
            int nonce = random.Next(1000, 9999);

            if (_dic.TryGetValue(timeStamp, out List<int> value))
            {
                //重新获取随机数
                if (value.Contains(nonce))
                {
                    return GenerateNonce(timeStamp);
                }
                else
                {
                    value.Add(nonce);
                    _dic.Remove(timeStamp);
                    _dic.Add(timeStamp, value);
                }
            }
            else
            {
                _dic.Clear();
                _dic.Add(timeStamp, new List<int> { nonce });
            }
            return nonce.ToString();
        }
复制代码

定义 lock 变量,可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。

定义 _dic 变量,用键值对的方式存储时间戳 +  随机数(nonce),以时间戳  timeStamp 作 Key , 并保存同一时间戳  timeStamp 下的所有随机数集合,作为键值。

若为同一时间戳下生成的订单号,获取到已存的随机数集合进行匹配,如果重复则重新生成新的随机数 nonce,确保不会出现重复值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static void Test()
{
    string orderId = "";
    //创建包含两个线程的数组
    TaskFactory factory = new TaskFactory();
    Task[] tasks = new Task[]
    {
      factory.StartNew(new Action(GenerateId)),
      factory.StartNew(()=> GenerateId())
    };
    Task.WaitAll(tasks);
    Console.WriteLine(orderId);
 
    
}
 
private static void GenerateId()
{
    for (var i = 0; i < 100; i++)
    {
        orderId +=  GeneratOrderNo(ContractType.Tag) + System.Environment.NewLine;
    }
    orderId += "--------------------------------" + System.Environment.NewLine;
}

 

另附上生成二十位随机数【10时间戳 + 10位递增值】的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
/// 根据时间戳生成20位编号
/// </summary>
/// <returns></returns>
public static string GenerateId()
{
    lock (_lock)//lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。
    {
        if (_num == int.MaxValue)
        {
            _num = 0;
        }
        else
        {
            _num++;
        }
        TimeSpan timespan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        string timeStamp = Convert.ToInt64(timespan.TotalSeconds).ToString();
 
        Thread.Sleep(10);
        return timeStamp + _num.ToString().PadLeft(10, '0');
    }
}

  

 

posted @   云水边静沐暖阳丶  阅读(577)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示