在SpringBoot中實現(xiàn)一個訂單號生成系統(tǒng)的示例代碼
1. UUID
最簡單的方法是使用UUID生成唯一的訂單號。UUID(Universally Unique Identifier)是一種廣泛使用的標識符,由128位組成,通常以32個十六進制數(shù)字表示,分為五組,形式為8-4-4-4-12的字符串,例如123e4567-e89b-12d3-a456-426614174000。UUID全球唯一,實現(xiàn)簡單,但缺點是UUID較長,不易記憶和存儲。
實例代碼
Java中生成UUID的示例代碼如下:
import java.util.UUID;
public class UUIDGenerator {
public static String generateUUID() {
// 生成一個UUID
UUID uuid = UUID.randomUUID();
// 將UUID轉換為字符串
String uuidAsString = uuid.toString();
// 返回UUID字符串
return uuidAsString;
}
public static void main(String[] args) {
String uuid = generateUUID();
System.out.println("Generated UUID: " + uuid);
}
}
2. 數(shù)據(jù)庫序列或自增ID
利用數(shù)據(jù)庫的序列(如PostgreSQL的SEQUENCE)或自增ID(如MySQL的AUTO_INCREMENT)生成唯一的訂單號。數(shù)據(jù)庫序列或自增ID是一種常見的生成唯一標識符的方法,特別是在單體應用或非分布式系統(tǒng)中。這種方法依賴于數(shù)據(jù)庫的內置機制來保證每次插入新記錄時自動產生一個唯一的標識符,缺點是難以在分布式環(huán)境中維護唯一性。
// 假設使用JPA
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// 其他屬性
}
數(shù)據(jù)庫序列(如PostgreSQL的SEQUENCE)
CREATE SEQUENCE order_id_seq START WITH 1 INCREMENT BY 1;
CREATE TABLE orders (
order_id bigint NOT NULL DEFAULT nextval('order_id_seq'),
order_data text
);
自增ID(如MySQL的AUTO_INCREMENT)
CREATE TABLE orders (
order_id INT AUTO_INCREMENT,
order_data TEXT,
PRIMARY KEY (order_id)
);
3. 時間戳+隨機數(shù)/序列
結合時間戳和隨機數(shù)(或自定義序列)生成訂單號,以保證唯一性和可讀性??梢酝ㄟ^添加業(yè)務相關的前綴來增強業(yè)務相關性。
實例代碼
以下是一個簡單的Java示例,展示了如何結合時間戳、隨機數(shù)和業(yè)務前綴生成訂單號:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ThreadLocalRandom;
public class OrderNumberGenerator {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
private static final int RANDOM_NUM_BOUND = 10000; // 定義隨機數(shù)范圍
public static String generateOrderNumber(String prefix) {
// 生成時間戳部分
String timestamp = dateFormat.format(new Date());
// 生成隨機數(shù)部分
int randomNumber = ThreadLocalRandom.current().nextInt(RANDOM_NUM_BOUND);
// 組合成訂單號
return prefix + timestamp + String.format("%04d", randomNumber);
}
public static void main(String[] args) {
// 示例:生成訂單號,假設業(yè)務前綴為"ORD"
String orderNumber = generateOrderNumber("ORD");
System.out.println("Generated Order Number: " + orderNumber);
}
}
4. 分布式唯一ID生成方案
在分布式系統(tǒng)中,可以使用像Twitter的Snowflake算法生成唯一的ID。Snowflake算法可以生成一個64位的長整數(shù),其中包含時間戳、數(shù)據(jù)中心ID、機器ID和序列號,以確保生成的ID既唯一又有序。
Snowflake ID結構
Snowflake生成的64位ID可以分為以下幾個部分:
- 1位符號位:由于整數(shù)的最高位是符號位,且64位整數(shù)中的最高位為符號位,通常這一位為0,保證ID為正數(shù)。
- 41位時間戳位:記錄時間戳的差值(相對于某個固定的時間點),單位到毫秒。41位時間戳可以使用69年。
- 10位數(shù)據(jù)中心ID和機器ID:通常分為5位數(shù)據(jù)中心ID和5位機器ID,最多支持32個數(shù)據(jù)中心,每個數(shù)據(jù)中心最多支持32臺機器。
- 12位序列號:用來記錄同一毫秒內生成的不同ID,12位序列號支持每個節(jié)點每毫秒產生4096個ID序號。
以下是一個簡化的Snowflake算法實現(xiàn)示例:
public class SnowflakeIdGenerator {
private long datacenterId; // 數(shù)據(jù)中心ID
private long machineId; // 機器ID
private long sequence = 0L; // 序列號
private long lastTimestamp = -1L; // 上一次時間戳
private final long twepoch = 1288834974657L;
private final long datacenterIdBits = 5L;
private final long machineIdBits = 5L;
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long maxMachineId = -1L ^ (-1L << machineIdBits);
private final long sequenceBits = 12L;
private final long machineIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + machineIdBits;
private final long timestampLeftShift = sequenceBits + machineIdBits + datacenterIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
public SnowflakeIdGenerator(long datacenterId, long machineId) {
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException("datacenterId can't be greater than %d or less than 0");
}
if (machineId > maxMachineId || machineId < 0) {
throw new IllegalArgumentException("machineId can't be greater than %d or less than 0");
}
this.datacenterId = datacenterId;
this.machineId = machineId;
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(machineId << machineIdShift) |
sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
}
下面是對這段代碼的逐行解釋:
類定義和變量初始化
private long datacenterId;定義數(shù)據(jù)中心ID。private long machineId;定義機器ID。private long sequence = 0L;序列號,用于同一毫秒內生成多個ID時區(qū)分這些ID。private long lastTimestamp = -1L;上一次生成ID的時間戳。
以下是Snowflake算法的一些關鍵參數(shù):
private final long twepoch = 1288834974657L;系統(tǒng)的起始時間戳,這里是Snowflake算法的作者選擇的一個固定的時間點(2010-11-04 09:42:54.657 GMT)。private final long datacenterIdBits = 5L;數(shù)據(jù)中心ID所占的位數(shù)。private final long machineIdBits = 5L;機器ID所占的位數(shù)。private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);數(shù)據(jù)中心ID的最大值,這里通過位運算計算得出。private final long maxMachineId = -1L ^ (-1L << machineIdBits);機器ID的最大值,同樣通過位運算得出。private final long sequenceBits = 12L;序列號占用的位數(shù)。
以下是一些用于位運算的參數(shù),用于計算最終的ID:
private final long machineIdShift = sequenceBits;機器ID的偏移位數(shù)。private final long datacenterIdShift = sequenceBits + machineIdBits;數(shù)據(jù)中心ID的偏移位數(shù)。private final long timestampLeftShift = sequenceBits + machineIdBits + datacenterIdBits;時間戳的偏移位數(shù)。private final long sequenceMask = -1L ^ (-1L << sequenceBits);用于保證序列號在指定范圍內循環(huán)。
構造函數(shù)
- 構造函數(shù)
SnowflakeIdGenerator(long datacenterId, long machineId)接收數(shù)據(jù)中心ID和機器ID作為參數(shù),并對這些參數(shù)進行校驗,確保它們在合法范圍內。
ID生成方法
public synchronized long nextId()是生成ID的核心方法,使用synchronized保證線程安全。- 首先獲取當前時間戳。
- 如果當前時間戳小于上一次生成ID的時間戳,拋出異常,因為時鐘回撥會導致ID重復。
- 如果當前時間戳等于上一次的時間戳(即同一毫秒內),通過增加序列號生成不同的ID;如果序列號溢出(超過最大值),則等待到下一個毫秒。
- 如果當前時間戳大于上一次的時間戳,重置序列號為0。
- 最后,將時間戳、數(shù)據(jù)中心ID、機器ID和序列號按照各自的偏移量左移,然后進行位或運算,組合成一個64位的ID。
輔助方法
private long tilNextMillis(long lastTimestamp)是一個輔助方法,用于在序列號溢出時等待直到下一個毫秒。
以上就是在SpringBoot中設計一個訂單號生成系統(tǒng)的示例代碼的詳細內容,更多關于SpringBoot訂單號生成系統(tǒng)的資料請關注腳本之家其它相關文章!
相關文章
dubbo將異常轉換成RuntimeException的原因分析?ExceptionFilter
這篇文章主要介紹了dubbo將異常轉換成RuntimeException的原因分析?ExceptionFilter問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03
探索Java中private方法添加@Transactional事務未生效原因
你又遇到過明明給private方法添加了@Transactional但是事務依然沒有生效的情況嗎,具體原因本篇文章將詳細告訴你,有需要的朋友跟著小編往下看吧2021-11-11

