• 030 流水号的生成


      公司的流水号生成规则有一个bug需要修复,顺便查查资料,看看人家都怎么做的,这里稍微整理了一些。

    一:第一种方式

    1.需求加分析

      日期+ long(商家Id+订单类型+主机ID+AtomicInteger),什么意思呢,前面的日期保持不变,后面的将商家Id,订单的类型,主机的Id,AtomicInteger,通过移位与或运算“保存”到一个long类型里面。为什么要这么做?

    1. 不想把相关信息直接暴露出去。
    2. 通过流水号可以快速得到相关业务信息,快速定位问题。
    3. 使用AtomicInteger可提高并发量,降低了冲突。

    2.原理

      

    1. 符号位,这个不用过的介绍,大家都知道2进制第一位都是符号位,0表示正数1表示负数
    2. 当前秒数,表述的是当前是当天的第多少秒,每天最多有86400秒,最多占17位
    3. 商家Id占14位,由于业务涉及到商户,订单也是归为每个商户下面的,假定我们的最多有9999家商户,9999占位是14位,所以我们商户Id占14位,大家根据自身业务的量来决定长度。
    4. 订单类型,假定我们的订单类型还停留在10种以内,所以我们保留4位,最多支持类型16种,大家同样的根据业务的量来决定
    5. 服务器的Id,假定服务器数量在10台以内,所以我们保留4位,最多支持16台服务器,大家同样的根据自身服务器的数量来决定。,
    6. 剩下的24位全部留给AtomicInteger,设计上我这里的qps可以达到2的24方。这个其实已经很大了。大家根据上面的设计留下来的数量当AtomicInteger位数,其实可以满足大部分业务需求了。

     3.程序大纲

      

    4.TimeUtil.java

     1 package com.jun.it;
     2 
     3 import java.text.SimpleDateFormat;
     4 import java.util.Calendar;
     5 import java.util.Date;
     6 import java.util.GregorianCalendar;
     7 
     8 public class TimeUtil {
     9     public static final String DATE_FORMAT_PATTERN_DEFAULT = "yyyy-MM-dd HH:mm:ss";
    10     public static final String DATE_FORMAT_PATTERN_NO_SECOND = "yyyy-MM-dd HH:mm";
    11     public static final String DATE_FORMAT_PATTERN_HTTP = "EEE, dd-MMM-yyyy HH:mm:ss z";
    12     public static final String DATE_FORMAT_PATTERN_SHORT = "yyyy-MM-dd";
    13     public static final String DATE_FORMAT_PATTERN_INT = "yyyyMMdd";
    14     public static final String DATE_FORMAT_PATTERN_NO_SEPARATOR = "yyyyMMddHHmmss";
    15     public static final String DATE_FORMAT_PATTERN_MONTH_INT = "yyyyMM";
    16 
    17     public static int toSeconds() {
    18         return (int) (System.currentTimeMillis() / 1000);
    19     }
    20 
    21     public static int toSeconds(Date date) {
    22         if (date != null) {
    23             return (int) (date.getTime() / 1000);
    24         }
    25         return 0;
    26     }
    27 
    28 
    29     public static Date floor(Date date) {
    30         Calendar calendar = new GregorianCalendar();
    31         calendar.setTime(date);
    32         calendar.set(Calendar.HOUR_OF_DAY, 0);
    33         calendar.set(Calendar.MINUTE, 0);
    34         calendar.set(Calendar.SECOND, 0);
    35         calendar.set(Calendar.MILLISECOND, 0);
    36         return calendar.getTime();
    37     }
    38 
    39     public static Date ceiling(Date date) {
    40         Calendar calendar = new GregorianCalendar();
    41         calendar.setTime(date);
    42         calendar.set(Calendar.HOUR_OF_DAY, 23);
    43         calendar.set(Calendar.MINUTE, 59);
    44         calendar.set(Calendar.SECOND, 59);
    45         calendar.set(Calendar.MILLISECOND, 999);
    46         return calendar.getTime();
    47     }
    48 
    49     public static String format(Date date, String formatString) {
    50         if (date == null) {
    51             date = new Date();
    52         }
    53         return new SimpleDateFormat(formatString).format(date);
    54     }
    55 
    56     public static int toInt(Date date) {
    57         if (date != null) {
    58             return Integer.parseInt(format(date, DATE_FORMAT_PATTERN_INT));
    59         }
    60         return 0;
    61     }
    62 
    63     public static Date now() {
    64         return new Date();
    65     }
    66 
    67 
    68     public static void main(String[] args) {
    69         System.out.println(floor(new Date()));
    70         System.out.println(ceiling(new Date()));
    71         System.out.println(now());
    72         System.out.println(toInt(new Date()));
    73     }
    74 }

    5.SerialNumberDemo.java

      这里的方式是优雅了许多,是通过移位,然后或的方式拼接而成。

     1 package com.jun.it;
     2 
     3 import java.util.Date;
     4 import java.util.concurrent.atomic.AtomicInteger;
     5 
     6 public class SerialNumberDemo {
     7      private static final AtomicInteger SERIAL = new AtomicInteger(Integer.MAX_VALUE);
     8         private static final int SHIFTS_FOR_TIMESTAMP = 17;
     9         private static final int SHIFTS_FOR_UNION = 14;
    10         private static final int SHIFTS_FOR_TYPE = 4;
    11         private static final int SHIFTS_FOR_NODE = 4;
    12         private static final int SHIFTS_FOR_SERIAL = 24;
    13         private static final int MASK_FOR_SERIAL = (1 << SHIFTS_FOR_SERIAL) - 1;
    14         private static final long MASK_FOR_UNION = (1 << SHIFTS_FOR_UNION) - 1;
    15         private static final long MASK_FOR_TYPE = (1 << SHIFTS_FOR_TYPE) - 1;
    16 
    17         public static String next(long mechId, long type) {
    18             long second = TimeUtil.toSeconds() - TimeUtil.toSeconds(TimeUtil.floor(new Date()));
    19             long serverId = 1; //这个地方应该可以根据tomcat参数来设置的,通过或tomcat参数来获取服务器id
    20             long serial = SERIAL.incrementAndGet();
    21             long secondShift = second << (64 - 1 - SHIFTS_FOR_TIMESTAMP);
    22             long unionShift = mechId << (64 - 1 - SHIFTS_FOR_TIMESTAMP - SHIFTS_FOR_UNION);
    23             long typeShift = type << (64 - 1 - SHIFTS_FOR_TIMESTAMP - SHIFTS_FOR_UNION - SHIFTS_FOR_TYPE);
    24             long nodeShift = serverId << (64 - 1 - SHIFTS_FOR_TIMESTAMP - SHIFTS_FOR_UNION - SHIFTS_FOR_TYPE - SHIFTS_FOR_NODE);
    25             long number = secondShift | unionShift | typeShift | nodeShift | (serial & MASK_FOR_SERIAL);
    26             return String.valueOf(TimeUtil.toInt(new Date())) + String.valueOf(number);
    27         }
    28 
    29         public static long getSecond(long id) {
    30             return id >> (SHIFTS_FOR_UNION + SHIFTS_FOR_TYPE + SHIFTS_FOR_NODE + SHIFTS_FOR_SERIAL);
    31         }
    32 
    33         public static long getMechId(long id) {
    34             return (id >> (SHIFTS_FOR_TYPE + SHIFTS_FOR_NODE + SHIFTS_FOR_SERIAL)) & MASK_FOR_UNION;
    35         }
    36 
    37         public static long getType(long id) {
    38             return (id >> (SHIFTS_FOR_NODE + SHIFTS_FOR_SERIAL)) & MASK_FOR_TYPE;
    39         }
    40 
    41 
    42         public static void main(String[] args) {
    43             String number = next(14, 4);
    44             System.out.println(number);  
    45             System.out.println("秒数:"+getSecond(5709508857563185152L));
    46             System.out.println("商户Id:"+getMechId(5709508857563185152L));
    47             System.out.println("订单类型:"+getType(5709508857563185152L));
    48         }
    49 }

    6.效果

      

    二:

  • 相关阅读:
    Python PEP—Python增强提案
    容器技术介绍:Docker简介及安装
    Python笔记:List相关操作
    Python笔记:字符串操作
    Python笔记:属性值设置和判断变量是否存在
    mitmproxy 代理工具介绍:rewrite和map local实现
    接口测试代理工具charles mock测试
    接口测试框架Requests
    JMeter性能测试:JMeter安装及脚本录制回放
    PHP Parse error: parse error, unexpected T_OBJECT_OPERATOR
  • 原文地址:https://www.cnblogs.com/juncaoit/p/9615622.html
Copyright © 2020-2023  润新知