zoukankan      html  css  js  c++  java
  • 订单号生成逻辑,C#和JAVA双版

    五年没写过博客了,倒是天天在看

    转来转去,又转回技术

    原来一直在使用微软爸爸的东西,最近一两年开始玩android,玩java,还有PostgreSQL

    都有些应用了,倒是可以整理些随笔出来,这就是其中一篇吧

    c#是java的优雅版本,java的linq就是一坨那啥,嗯!觉得不爽就别看了

    订单号这个玩意我想有几点得保证

    1,有顺序但不连续

    2,不能太长,最好15位以内

    3,最好全数字

    目前来说谷歌和百度出来的感觉都达不到我要的这些要求,不是太长超过20位,就是会加上字母,再就是会连续,否则就没顺序,没有办法只有自己想

    本来没想自己干的,这玩意绝对是个老问题,估计大家都有好办法,藏着了吧

    开干,思路如下:

    得有时间在里面,这样有顺序

    不连续好办,加上随机尾数

    不能太长也好办,取一部分时间戳,或者是当前时间减去过去一个固定时间的差值

    OK,上代码,先JAVA

      1 import java.io.*;
      2 import java.util.UUID;
      3 import java.util.concurrent.atomic.AtomicLong;
      4 
      5 /**
      6  * Created by 黑曜石 on 2017/5/19.
      7  */
      8 public class TradeNoGenerator {
      9     //基准时间截 (2017-01-01)
     10     private static final long initStamp=1483200000000L;
     11     //每秒基准容量1000个
     12     private static final int secondsSpace=1000;
     13     //基准容量扩容倍数
     14     private static final int secondsSpaceMulti=10;
     15     //多少秒不用,重新设定原子初始值
     16     private static final int secondsRefresh=60;
     17     //原子初始值
     18     private AtomicLong atomicLong=new AtomicLong((System.currentTimeMillis()-initStamp)*secondsSpaceMulti);
     19 
     20     private TradeNoGenerator() {
     21     }
     22 
     23     private static class TradeNoGeneratorHolder{
     24         private static TradeNoGenerator instance = new TradeNoGenerator();
     25     }
     26 
     27     public static TradeNoGenerator getInstance() {
     28         return TradeNoGeneratorHolder.instance;
     29     }
     30 
     31     //线程安全
     32     /**
     33      * 用这个,用这个
     34      * @return
     35      * 生成结果例:11983017246298
     36      * 由三段组成,11983017,2462,98
     37      * 第一段11983017,位数会随着时间增长增加,计算方式为与initStamp相加,结果为到秒的时间戳
     38      * 第二段,2462,看容量决定位数,容量=secondsSpace*secondsSpaceMulti,原子增长字段
     39      * 第三段98,固定2位,随机数
     40      */
     41     public synchronized String getNo(){
     42         long no=atomicLong.getAndIncrement();
     43         //当前秒时间戳与基准时间戳秒级数量
     44         long currentSecond = (System.currentTimeMillis()-initStamp) / 1000;
     45         //计数超过60秒未使用过,则重新给定初始值
     46         if (currentSecond-no/(secondsSpace*secondsSpaceMulti)>=secondsRefresh){
     47             //重置原子计数原始值
     48             atomicLong=new AtomicLong((System.currentTimeMillis()-initStamp)*secondsSpaceMulti);
     49             no=atomicLong.getAndIncrement();
     50         }
     51         //计算容量是否超出
     52         if (no-currentSecond*secondsSpace*secondsSpaceMulti>=secondsSpace*secondsSpaceMulti){
     53             //超出则等待下一秒的到来,这里计算到下一整数秒的微秒差
     54             long millisWithinSecond = System.currentTimeMillis() % 1000;
     55             try {
     56                 Thread.sleep(1000 - millisWithinSecond);
     57             } catch (InterruptedException e) {
     58                 e.printStackTrace();
     59             }
     60 
     61             System.out.println(">>> new second . "+no +" "+Thread.currentThread().getName());
     62 
     63             //重置原子计数原始值
     64             atomicLong=new AtomicLong((System.currentTimeMillis()-initStamp)*secondsSpaceMulti);
     65             no=atomicLong.getAndIncrement();
     66         }
     67 
     68         int hashCode= UUID.randomUUID().hashCode();
     69         hashCode=hashCode<0?-hashCode:hashCode;
     70         String randomStr=String.valueOf(hashCode).substring(0,2);
     71         return no+randomStr;
     72     }
     73 
     74     /**
     75      * 获取时间戳
     76      * @param tradeNo
     77      * @return
     78      */
     79     public long getTimestamp(String tradeNo){
     80         int spaceLen = String.valueOf(secondsSpace*secondsSpaceMulti).length()-1;
     81         int stampLen=tradeNo.length()-spaceLen-2;
     82         String stampStr=tradeNo.substring(0,stampLen);
     83         //右侧补齐微秒
     84         long stamp=Long.parseLong(stampStr+String.format("%1$03d",0));
     85         stamp+=initStamp;
     86         return stamp;
     87     }
     88 
     89     public static void main(String[] args) {
     90 
     91         File file=new File("e:/tradeno1.txt");
     92         if (file.exists()){
     93             file.delete();
     94         }
     95         try {
     96             file.createNewFile();
     97         } catch (IOException e) {
     98             e.printStackTrace();
     99         }
    100         file=new File("e:/tradeno2.txt");
    101         if (file.exists()){
    102             file.delete();
    103         }
    104         try {
    105             file.createNewFile();
    106         } catch (IOException e) {
    107             e.printStackTrace();
    108         }
    109 
    110         new Thread(new Runnable() {
    111             @Override
    112             public void run() {
    113 
    114                 try {
    115                     Writer w=new FileWriter("e:/tradeno1.txt");
    116                     BufferedWriter buffWriter=new BufferedWriter(w);
    117 
    118                     TimeMark timeMark=new TimeMark();
    119                     for (int i = 0; i < 12000; i++) {
    120                         String x=getInstance().getNo();
    121                         //System.out.println(x);
    122                         buffWriter.write(x+"	
    ");
    123                     }
    124                     System.out.println("]]]");
    125                     timeMark.simplePrint();
    126 
    127                     buffWriter.close();
    128                     w.close();
    129                     System.out.println("写入成功!");
    130 
    131                 } catch (FileNotFoundException e) {
    132                     System.out.println("要读取的文件不存在:"+e.getMessage());
    133                 } catch (IOException e) {
    134                     System.out.println("文件读取错误:"+e.getMessage());
    135                 }
    136             }
    137         }).start();
    138 
    139         new Thread(new Runnable() {
    140             @Override
    141             public void run() {
    142                 try {
    143                     Writer w=new FileWriter("e:/tradeno2.txt");
    144                     BufferedWriter buffWriter=new BufferedWriter(w);
    145 
    146                     TimeMark timeMark=new TimeMark();
    147                     for (int i = 0; i < 24000; i++) {
    148                         String x=getInstance().getNo();
    149                         //System.out.println(x);
    150                         buffWriter.write(x+"	
    ");
    151                     }
    152                     System.out.println("]]]");
    153                     timeMark.simplePrint();
    154 
    155                     buffWriter.close();
    156                     w.close();
    157                     System.out.println("写入成功!");
    158 
    159                 } catch (FileNotFoundException e) {
    160                     System.out.println("要读取的文件不存在:"+e.getMessage());
    161                 } catch (IOException e) {
    162                     System.out.println("文件读取错误:"+e.getMessage());
    163                 }
    164             }
    165         }).start();
    166     }
    167 }

    接下来是C#

    public class TradeNoGenerator
        {
            //基准时间截 (2017-01-01)
            private static DateTime initDateTime = new DateTime(2017, 1, 1);
            //每秒基准容量1000个
            private static int secondsSpace = 1000;
            //基准容量扩容倍数
            private static int secondsSpaceMulti = 10;
            //多少秒不用,重新设定原子初始值
            private static int secondsRefresh = 60;
            //原子初始值
            private static long initStamp = (long)DateTime.UtcNow.Subtract(initDateTime).TotalSeconds * secondsSpace * secondsSpaceMulti;
    
            static TradeNoGenerator __TradeNoGenerator;
            private TradeNoGenerator()
            {
            }
    
            public static TradeNoGenerator GetInstance()
            {
                if (__TradeNoGenerator == null)
                {
                    __TradeNoGenerator = new TradeNoGenerator();
                }
                return __TradeNoGenerator;
            }
    
            //线程安全
            /**
             * 用这个,用这个
             * @return
             * 生成结果例:11983017246298
             * 由三段组成,11983017,2462,98
             * 第一段11983017,位数会随着时间增长增加,计算方式为与initStamp相加,结果为到秒的时间戳
             * 第二段,2462,看容量决定位数,容量=secondsSpace*secondsSpaceMulti,原子增长字段
             * 第三段98,固定2位,随机数
             */
            public String GetNo()
            {
                long no = Interlocked.Increment(ref initStamp);
                //当前秒时间戳与基准时间戳秒级数量
                double currentSecond = DateTime.UtcNow.Subtract(initDateTime).TotalSeconds;
                //计数超过60秒未使用过,则重新给定初始值
                if (currentSecond - no / (secondsSpace * secondsSpaceMulti) >= secondsRefresh)
                {
                    //重置原子计数原始值
                    initStamp= (long)DateTime.UtcNow.Subtract(initDateTime).TotalSeconds * secondsSpace * secondsSpaceMulti;
                    no = Interlocked.Increment(ref initStamp);
                }
                //计算容量是否超出
                if (no - currentSecond * secondsSpace * secondsSpaceMulti >= secondsSpace * secondsSpaceMulti)
                {
                    //超出则等待下一秒的到来,这里计算到下一整数秒的微秒差
                    int millisWithinSecond = DateTime.UtcNow.Millisecond % 1000;
                    try
                    {
                        Thread.Sleep(1000 - millisWithinSecond);
                    }
                    catch (Exception ex)
                    {
                        
                    }
    
                    //重置原子计数原始值
                    initStamp = (long)DateTime.UtcNow.Subtract(initDateTime).TotalSeconds * secondsSpace * secondsSpaceMulti;
                    no = Interlocked.Increment(ref initStamp);
                }
    
                int hashCode = Guid.NewGuid().GetHashCode();
                hashCode = hashCode < 0 ? -hashCode : hashCode;
                String randomStr = hashCode.ToString().Substring(0, 2);
                return no + randomStr;
            }
        }

    注释写得很清楚啦

    1秒基准容量是1000个,可以以10的倍数来扩大(只能是10的倍数),一般扩大10倍,1秒容量到10000个,可以解决很多问题啦

    速度你们可以自己测试,一秒内的速度是毫秒级别的

    超出秒容量的话,那就得等待下一秒的到来

    还有个问题就是当前不支持分布式

    无论是JAVA还是C#基本是利用原子自增方式解决并发和效率问题

  • 相关阅读:
    企业微信中如何屏蔽另外一个企业的消息
    国际商标注册里面的头头道道
    如何使用charles,常见的charles功能
    Win8中GridVIew千变万化——绑定分组数据
    Win8中ListBox的ScrollIntoView方法失效
    一起零基础通过Nosql考试~~
    Ubuntu部署ros小龟爬爬实例
    学习算法是件怎样的事
    Centos7配置Python3.10.1
    基于Centos7、PHP7.4环境部署wordpress
  • 原文地址:https://www.cnblogs.com/bestfc/p/7447964.html
Copyright © 2011-2022 走看看