.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,确保不会出现重复值。

        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位递增值】的方法:

        /// <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 @ 2022-04-01 14:19  云水边静沐暖阳丶  阅读(445)  评论(0编辑  收藏  举报