订单号生成逻辑,C#和JAVA双版

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+"\t\r");

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+"\t\r");

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#基本是利用原子自增方式解决并发和效率问题

以上是 订单号生成逻辑,C#和JAVA双版 的全部内容, 来源链接: utcz.com/z/391127.html

回到顶部