c#生成不重复订单号(16位),不需要确认数据库,商城网站建设中常用。
  • 作者:admin
  • 最后更新:2018-08-07
  • 来源:国尚网络

如题:在生成订单号时,如何确保订单号的唯一性与高效性,这是一个不太好办的技术问题。在百度上查了一下,大体上都一样,还在网上看到有这样的需求,产生一个16字符的订单号,要订单唯一还要能支撑大负荷压力。网上的搜索结果要不用guid/uuid,要不就简单的用时间加随机数。用guid基本可以确定唯一性,但因为有概率问题,最好还要通过数据库去核实有没有重复,另外,guid不利于订单的排序,去年的订单与今天的订单可能在查询结果上处在一块,因此不推荐使用。本文介绍的生成订单号的方法(c#实现的),应该可以为大家提供一个思路的参考。先说一下思路:1.实现:采用时间信息来标识订单是一个好的想法。但在微观尺度上,时间的秒与毫秒就会显的尺度很大,程序很容易在1秒内生成多个订单号,因此还需要添加一个流水号,流水号有多大容量,程序就可以在1秒内生成多少个订单号。2.要求:订单号应当尽量简短。时间的字符串加起来也不短,如:2015-06-24  11: 12:55,去掉非字符是(4+2+2+2*3)总共14个字符,如果将时间改为16进制存储,则可以省略到10个字符以内。其它6位可以让给流水号使用。3.结果:订单号可以追溯到用户下单的秒级别时间;订单号流水在秒级别内可以达到0xFFFFFF的空量,即:16777215个订单,即每秒中理论可以达到1600万个以上的订单号,而且不重复。订单号可以排序:如果存储字符,可以按字符排序,同一个时间段的订单会在一起。如果把订单号转换成数字存储则可以精确排序。当前时间中的日期,按从0001-01-01起到现在的天数,采用16进制存储,比如今天是2015-06-24,换算成天数:2015*365+6*30+24=735679天,换算成16进制:B39BF,仅占5个字符。而5个字符的空量(0xFFFFF的空量)是1048575天,换算成年:2872年。现在是2015年,可以用到850年以后,放心了吧!如果从2000年算起,仅2个字符就行,占用容量更小,其它3个字符位置可以更多的给订单流水号使用或附加其它信息。当前天中的秒数同理,只是从今天0时开始计算,也是5个字符,不再辍述。现在贴出代码:   

public class OrderForm    {       

*****       

private static long np1 = 0,np2 = 0,np3 = 1; //临时计算用。       

private static object orderFormNumberLock = new object();//线程并行锁,以保证同一时间点只有一个用户能够操作流水号。如果分多个流水号段,放多个锁,并行压力可以更好的解决,大家自己想法子扩充吧       

private string strOrderNumber = null;//订单号。       

****        

其它操作、属性,此处内容省略。       

****       

/// <summary>       

/// 初始化订单号码       

/// 编码规则:(16进制,从DateTime.MinValue起到此时的)总天数 + 今天的总秒数 + 当前秒内产生的订单序号,其中今天的订单序号每秒清零。       

/// 该方法线程安全。       

/// </summary>       

public void InitializeOrderNumber()        {

            DateTime now = DateTime.Now; 

           TimeSpan span = now - DateTime.MinValue;

            long tmpDays = span.Days;

            long seconds = span.Hours * 3600 + span.Seconds;

            StringBuilder sb = new StringBuilder();

            Monitor.Enter(orderFormNumberLock); 

//锁定资源           

if(tmpDays != np1){

                np1 = tmpDays; 

               np2 = 0;

                np3 = 1; 

           } 

           if (np2 != seconds) 

           {

                np2 = seconds;

                np3 = 1; 

           }

            sb.Append(Convert.ToString(np1, 16).PadLeft(5, '0') + Convert.ToString(np2, 16).PadLeft(5, '0') + Convert.ToString(np3++, 16).PadLeft(6, '0'));

            Monitor.Exit(orderFormNumberLock); //释放资源

            strOrderNumber = sb.ToString();

        }

        /// <summary>

        /// 获取订单号表示的日期 

       /// 即:反向获取订单号的日期

        /// </summary>

        public DateTime DateTimeFromOrderNumber

        {

            get

            {

                if (!string.IsNullOrEmpty(OrderNumber))

                {

                    return DateTime.MinValue.AddDays(Convert.ToInt64(OrderNumber.Substring(0,5), 16)).AddSeconds(Convert.ToInt64("0x" + OrderNumber.Substring(5, 5), 16));

                }

                else

                { 

                   return DateTime.MinValue;

                }

            }

        }}

经过2线程各10000次循环并行自测,流水号一秒内最多可以用到4个字符,还保持两高位剩余。以上内容看上去稍复杂,下面是简单的版本

    public class OrderForm

    {

        private static string prevBase = string.Empty;//旧的订单号基础部分(精确到秒的字符串)

        private static object orderFormNumberLock = new object();//订单号共享锁

        private static long counter = 1;//订单号累加计数器

        private string orderNumber = string.Empty;//订单号。

        public void InitializeOrderNumber()

        {

            StringBuilder sb = new StringBuilder(); 

           Monitor.Enter(orderFormNumberLock);

            DateTime now = DateTime.Now;

            #region 短格式,从DateTime.MinValue以来的天数+小时数+分钟数+秒数+1秒内的排序号

            //TimeSpan span = now - DateTime.MinValue; 

           //long tmpDays = span.Days;

            //long seconds = span.Hours * 3600 + span.Seconds;

            //string newBase = Convert.ToString(tmpDays, 16).PadLeft(5, '0') + Convert.ToString((span.Hours * 3600 + span.Seconds), 16).PadLeft(5, '0'); 

           //if (prevBase != newBase)

            //{ 

           //      counter = 1;

            //      prevBase = newBase;           

//}           

//sb.Append(newBase + Convert.ToString(counter++, 16).PadLeft(6, '0'));

            #endregion

            #region 长格式,年+月+日+小时+分+秒+订单排序序号 

           string newBase = now.Year.ToString().PadLeft(4, '0') +

                now.Month.ToString().PadLeft(2, '0') + 

               now.Day.ToString().PadLeft(2, '0') +

                now.Hour.ToString().PadLeft(2, '0') +

                now.Minute.ToString().PadLeft(2, '0') +

                now.Second.ToString().PadLeft(2, '0');

            if (prevBase != newBase) 

           { 

              //秒数换了则重置计数器

                counter = 1;

                prevBase = newBase;

            } 

           sb.Append(newBase + counter.ToString().PadLeft(6, '0'));

//只要运行足够快,理论每秒钟可生成99万个单号不重复,至少几千个不会有问题。

            #endregion

            orderNumber = sb.ToString(); 

           Monitor.Exit(orderFormNumberLock);

        } 

  }

抛砖引玉,希望大家多交流。QQ号:13544698济南国尚网络技术有限公司,是以济南网站建设,网站优化为主营业务的一家济南网络公司,立志于给客户制作一个干净漂亮而又足够安全的网站,交付客户一个高水准的互联网商务环境。欢迎来电洽谈:0531-88017386。 

RELATEED CONSULTING
相关咨询
选择下列产品马上在线沟通
服务时间:9:30-18:00
你可能遇到了下面的问题
关闭右侧工具栏