生成订单号

生成订单号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package com.jsz.peini.common.util;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
*
* 流水号生成器
*
* @version v1.0
* @author wgl
*
*/
public class SNUtil {

private final static String str62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private final static int pixLen = 36;
private static volatile int pixOne = 0;
private static volatile int pixTwo = 0;
private static volatile int pixThree = 0;
private static volatile int pixFour = 0;

private static final AtomicInteger ATOM_INT = new AtomicInteger(0);
private static final int MAX_36 = 36 * 36 * 36 * 36;

/**
* 生成短时间内不会重复的长度为15位的字符串。<br/>
* 生成策略为获取自1970年1月1日零时零分零秒至当前时间的毫秒数的16进制字符串值,该字符串值为11位<br/>
* 并追加四位"0-z"的自增字符串.<br/>
* 如果系统时间设置为大于<b>2304-6-27 7:00:26<b/>的时间,将会报错!<br/>
* 由于系统返回的毫秒数与操作系统关系很大,所以本方法并不准确。本方法可以保证在系统返回的一个毫秒数内生成36的4次方个(1679616)ID不重复。<br/>
* 经过测试:该方法效率 比 create15_2 方法快一倍
* @return 15位短时间不会重复的字符串。<br/>
* @since JDK1.6
*/
public final static synchronized String create15() {
StringBuilder sb = new StringBuilder(15);// 创建一个StringBuilder
sb.append(Long.toHexString(System.currentTimeMillis()));// 先添加当前时间的毫秒值的16进制
pixFour++;
if (pixFour == pixLen) {
pixFour = 0;
pixThree++;
if (pixThree == pixLen) {
pixThree = 0;
pixTwo++;
if (pixTwo == pixLen) {
pixTwo = 0;
pixOne++;
if (pixOne == pixLen) {
pixOne = 0;
}
}
}
}
return sb.append(str62.charAt(pixOne)).append(str62.charAt(pixTwo)).append(str62.charAt(pixThree)).append(str62.charAt(pixFour))
.toString();
}
@SuppressWarnings("unused")
public final static String create15_2() {
StringBuilder sb = new StringBuilder(15);
sb.append(Long.toHexString(System.currentTimeMillis()));
ATOM_INT.compareAndSet(MAX_36, 0);
String str = longTo36(ATOM_INT.incrementAndGet());
if (str.length() == 1) {
sb.append("000").append(str);
} else if (str.length() == 2) {
sb.append("00").append(str);
} else if (str.length() == 3) {
sb.append("0").append(str);
} else {
sb.append(str);
}
return sb.toString();
}
/**
* 生成短时间内不会重复的长度为16位的字符串。<br/>
* 生成策略为获取自1970年1月1日零时零分零秒至当前时间的毫秒数的16进制字符串值,该字符串值为11位<br/>
* 并追加四位"0-z"的自增字符串.<br/>
* 如果系统时间设置为大于<b>2304-6-27 7:00:26<b/>的时间,将会报错!<br/>
* 由于系统返回的毫秒数与操作系统关系很大,所以本方法并不准确。本方法可以保证在系统返回的一个毫秒数内生成36的4次方个(1679616)ID不重复。<br/>
* 经过测试:该方法效率 比 create15_2 方法快一倍
* @return 15位短时间不会重复的字符串。<br/>
* @since JDK1.6
*/
@SuppressWarnings("unused")
public final static String create16Years() {
StringBuilder sb = new StringBuilder(15);
sb.append(new SimpleDateFormat("yyMMddHHmmss").format(new Date()));
ATOM_INT.compareAndSet(MAX_36, 0);
String str = longTo36(ATOM_INT.incrementAndGet());
if (str.length() == 1) {
sb.append("000").append(str);
} else if (str.length() == 2) {
sb.append("00").append(str);
} else if (str.length() == 3) {
sb.append("0").append(str);
} else {
sb.append(str);
}
return sb.toString();
}

/**
* 10进制转任意进制
* @param num Long型值
* @param base 转换的进制
* @return 任意进制的字符形式
*/
private static final String ten2Any(long num, int base) {
StringBuilder sb = new StringBuilder(7);
while (num != 0) {
sb.append(str62.charAt((int) (num % base)));
num /= base;
}
return sb.reverse().toString();
}

/**
* 将一个Long 值 转换为 62进制
* @param num
* @return
*/
public static final String longTo62(long num) {
return ten2Any(num, 62);
}

private static final String longTo36(long num) {
return ten2Any(num, 36);
}
public static void main(String[] args) {
long begin = System.currentTimeMillis();
int repeat = 0;
int times = 10000;
Map<String, Object> store = new HashMap<String, Object>();
String no = null;
for (int i = 0; i < times; i++) {
//no = create15();
//no = create15_2();
no = create16Years();
if(store.containsKey(no)){
repeat++;
}else{
store.put(no, 1);
}
if(i==times-1){
System.out.println(no);
}
}
long end = System.currentTimeMillis();
System.out.println("测试getBigOrderCode 重复概率:");
System.out.println("测试次数:"+times);
System.out.println("重复次数:"+repeat);
System.out.println("重复概率:"+( new BigDecimal(repeat).divide(new BigDecimal(times)) ) );
System.out.println("测试耗时:"+(end-begin));
}


}

class SNTester implements Runnable{

static Map<String, Object> store = new HashMap<String, Object>();
int times = 2000;
@Override
public void run() {
Map<String, Object> store = new HashMap<String, Object>();
String no = null;
for (int i = 0; i < times; i++) {
no = SNUtil.create15();
if(store.containsKey(no)){
//repeat++;
}else{
store.put(no, 1);
}
if(i==times-1){
System.out.println(no);
}
}

}

}
今天最好的表现,是明天最低的要求。