在我們的工作中,資料庫某些表的字段會用到唯一的,趨勢遞增的訂單編号,我們将介紹兩種方法,一種是傳統的采用随機數生成的方式,另外一種是采用目前比較流行的“分布式唯一ID生成算法-雪花算法”來實作。
一、時間戳随機數生成唯一ID
我們寫一個for循環,用
RandomUtil.generateOrderCode()生成1000個唯一ID,執行結果我們會發現出現重複的ID。
/**
* 随機數生成util
**/
public class RandomUtil {
private static final SimpleDateFormat dateFormatOne=new SimpleDateFormat("yyyyMMddHHmmssSS");
private static final ThreadLocalRandom random=ThreadLocalRandom.current();
//生成訂單編号-方式一
public static String generateOrderCode(){
//TODO:時間戳+N為随機數流水号
return dateFormatOne.format(DateTime.now().toDate()) + generateNumber(4);
}
//N為随機數流水号
public static String generateNumber(final int num){
StringBuffer sb=new StringBuffer();
for (int i=1;i<=num;i++){
sb.append(random.nextInt(9));
return sb.toString();
鑒于此種“基于随機數生成”的方式在高并發的場景下并不符合我們的要求,接下來,我們将介紹另外一種比較流行的、典型的方式,即“分布式唯一ID生成算法-雪花算法”來實作。
對于“雪花算法”的介紹,各位小夥伴可以參考Github上的這一連結,我覺得講得還是挺清晰的:
github/souyunku/SnowFlake ,詳細的Debug在這裡就不贅述了,下面截取了部分概述:
二、分布式唯一ID生成算法-雪花算法
我們寫一個for循環,用SNOW_FLAKE.nextId() 生成1000個唯一ID,發現不會出現重複的。
/* 雪花算法
*/
public class SnowFlake {
//起始的時間戳
private final static long START_STAMP=1480166465631L;
//每一部分占用的位數
private final static long SEQUENCE_BIT=12; //序列号占用的位數
private final static long MACHINE_BIT=5; //機器辨別占用的位數
private final static long DATA_CENTER_BIT=5;//
二手手遊賣号資料中心占用的位數
//每一部分的最大值
private final static long MAX_DATA_CENTER_NUM=-1L ^ (-1L << DATA_CENTER_BIT);
private final static long MAX_MACHINE_NUM=-1L ^ (-1L << MACHINE_BIT);
private final static long MAX_SEQUENCE=-1L ^ (-1L << SEQUENCE_BIT);
//每一部分向左的位移
private final static long MACHINE_LEFT=SEQUENCE_BIT;
private final static long DATA_CENTER_LEFT=SEQUENCE_BIT + MACHINE_BIT;
private final static long TIMESTAMP_LEFT=DATA_CENTER_LEFT + DATA_CENTER_BIT;
private long dataCenterId; //資料中心
private long machineId; //機器辨別
private long sequence=0L; //序列号
private long lastStamp=-1L;//上一次時間戳
public SnowFlake(long dataCenterId, long machineId) {
if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
throw new IllegalArgumentException("dataCenterId can't be greater than MAX_DATA_CENTER_NUM or less than 0");
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
this.dataCenterId=dataCenterId;
this.machineId=machineId;
//産生下一個ID
public synchronized long nextId() {
long currStamp=getNewStamp();
if (currStamp < lastStamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
if (currStamp==lastStamp) {
//相同毫秒内,序列号自增
sequence=(sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列數已經達到最大
if (sequence==0L) {
currStamp=getNextMill();
} else {
//不同毫秒内,序列号置為0
sequence=0L;
lastStamp=currStamp;
return (currStamp - START_STAMP) << TIMESTAMP_LEFT //時間戳部分
| dataCenterId << DATA_CENTER_LEFT //資料中心部分
| machineId << MACHINE_LEFT //機器辨別部分
| sequence; //序列号部分
private long getNextMill() {
long mill=getNewStamp();
while (mill <=lastStamp) {
mill=getNewStamp();
return mill;
private long getNewStamp() {
return System.currentTimeMillis();
綜上,我們在高并發大量生成唯一ID時,避免生成重複ID,需要用第二種雪花算法生成。