【JAVA】業務系統訂單號,流水號生成規則工具類

設計業務系統訂單號,流水號注意事項

  1. 唯一性:確保在分布式環境下ID不重復

  2. 有序性:ID隨時間遞增,有利于數據庫索引性能

  3. 可讀性:包含時間信息,便于人工識別

  4. 擴展性:支持業務前綴和類型區分

  5. 性能:本地生成,無網絡開銷

  6. 高并發:考慮線程安全,避免阻塞

根據實際業務需求,可以調整各部分位數分配,例如增加機器ID位數或減少序列號位數。

下面是一個完整的訂單號和流水號生成工具類實現,考慮了高并發、分布式環境下的唯一性需求。

訂單號/流水號生成工具類

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;

/**
?* 業務系統訂單號/流水號生成工具
?*/
public class SerialNumberGenerator {

? ? // 日期時間格式化器(線程安全)
? ? private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
? ??
? ? // 自增序列(單機環境下使用)
? ? private static final AtomicLong SEQUENCE = new AtomicLong(0);
? ??
? ? // 機器ID(分布式環境下使用)
? ? private static final String MACHINE_ID = initMachineId();
? ??
? ? /**
? ? ?* 生成訂單號(格式: ORDER + 時間 + 機器ID + 序列號)
? ? ?* 示例: ORDER2024051215230100110001
? ? ?*/
? ? public static String generateOrderNo() {
? ? ? ? return generateSerialNumber("ORDER");
? ? }
? ??
? ? /**
? ? ?* 生成交易流水號(格式: TRANS + 時間 + 機器ID + 序列號)
? ? ?* 示例: TRANS2024051215230100110001
? ? ?*/
? ? public static String generateTransNo() {
? ? ? ? return generateSerialNumber("TRANS");
? ? }
? ??
? ? /**
? ? ?* 通用序列號生成方法
? ? ?* @param prefix 前綴(如ORDER, TRANS等)
? ? ?*/
? ? private static String generateSerialNumber(String prefix) {
? ? ? ? StringBuilder sb = new StringBuilder(prefix);
? ? ? ??
? ? ? ? // 1. 添加時間部分(14位)
? ? ? ? sb.append(DATE_TIME_FORMATTER.format(LocalDateTime.now()));
? ? ? ??
? ? ? ? // 2. 添加機器ID(4位)
? ? ? ? sb.append(MACHINE_ID);
? ? ? ??
? ? ? ? // 3. 添加序列號(6位)
? ? ? ? sb.append(String.format("%06d", SEQUENCE.incrementAndGet() % 999999));
? ? ? ??
? ? ? ? // 4. 添加隨機后綴(2位)防止猜測
? ? ? ? sb.append(String.format("%02d", ThreadLocalRandom.current().nextInt(0, 99)));
? ? ? ??
? ? ? ? return sb.toString();
? ? }
? ??
? ? /**
? ? ?* 初始化機器ID(實際項目中可以從配置中心獲取)
? ? ?*/
? ? private static String initMachineId() {
? ? ? ? // 這里簡單演示,實際項目中可以從配置文件或配置中心獲取
? ? ? ? String machineId = System.getProperty("machine.id", "0001");
? ? ? ? return String.format("%04d", Integer.parseInt(machineId));
? ? }
? ??
? ? /**
? ? ?* 帶業務類型的訂單號生成
? ? ?* @param bizType 業務類型(2位字母)
? ? ?*/
? ? public static String generateBizOrderNo(String bizType) {
? ? ? ? if(bizType == null || bizType.length() != 2) {
? ? ? ? ? ? throw new IllegalArgumentException("業務類型必須為2位字母");
? ? ? ? }
? ? ? ? return generateSerialNumber("ORD" + bizType.toUpperCase());
? ? }
}

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;/*** 業務系統訂單號/流水號生成工具*/
public class SerialNumberGenerator {// 日期時間格式化器(線程安全)private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");// 自增序列(單機環境下使用)private static final AtomicLong SEQUENCE = new AtomicLong(0);// 機器ID(分布式環境下使用)private static final String MACHINE_ID = initMachineId();/*** 生成訂單號(格式: ORDER + 時間 + 機器ID + 序列號)* 示例: ORDER2024051215230100110001*/public static String generateOrderNo() {return generateSerialNumber("ORDER");}/*** 生成交易流水號(格式: TRANS + 時間 + 機器ID + 序列號)* 示例: TRANS2024051215230100110001*/public static String generateTransNo() {return generateSerialNumber("TRANS");}/*** 通用序列號生成方法* @param prefix 前綴(如ORDER, TRANS等)*/private static String generateSerialNumber(String prefix) {StringBuilder sb = new StringBuilder(prefix);// 1. 添加時間部分(14位)sb.append(DATE_TIME_FORMATTER.format(LocalDateTime.now()));// 2. 添加機器ID(4位)sb.append(MACHINE_ID);// 3. 添加序列號(6位)sb.append(String.format("%06d", SEQUENCE.incrementAndGet() % 999999));// 4. 添加隨機后綴(2位)防止猜測sb.append(String.format("%02d", ThreadLocalRandom.current().nextInt(0, 99)));return sb.toString();}/*** 初始化機器ID(實際項目中可以從配置中心獲取)*/private static String initMachineId() {// 這里簡單演示,實際項目中可以從配置文件或配置中心獲取String machineId = System.getProperty("machine.id", "0001");return String.format("%04d", Integer.parseInt(machineId));}/*** 帶業務類型的訂單號生成* @param bizType 業務類型(2位字母)*/public static String generateBizOrderNo(String bizType) {if(bizType == null || bizType.length() != 2) {throw new IllegalArgumentException("業務類型必須為2位字母");}return generateSerialNumber("ORD" + bizType.toUpperCase());}
}

第二種。雪花算法

對于分布式系統,推薦使用雪花算法(Snowflake)改進版:

import java.time.Instant;

/**
?* 分布式ID生成器(基于雪花算法改進)
?*/
public class DistributedIdGenerator {
? ? // 起始時間戳(2024-01-01)
? ? private final static long START_TIMESTAMP = 1704067200000L;
? ??
? ? // 機器ID所占位數
? ? private final static long WORKER_ID_BITS = 5L;
? ??
? ? // 數據中心ID所占位數
? ? private final static long DATACENTER_ID_BITS = 5L;
? ??
? ? // 序列號所占位數
? ? private final static long SEQUENCE_BITS = 12L;
? ??
? ? // 最大機器ID
? ? private final static long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
? ??
? ? // 最大數據中心ID
? ? private final static long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);
? ??
? ? // 機器ID左移位數
? ? private final static long WORKER_ID_SHIFT = SEQUENCE_BITS;
? ??
? ? // 數據中心ID左移位數
? ? private final static long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
? ??
? ? // 時間戳左移位數
? ? private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
? ??
? ? // 序列號掩碼
? ? private final static long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
? ??
? ? private final long workerId;
? ? private final long datacenterId;
? ? private long sequence = 0L;
? ? private long lastTimestamp = -1L;
? ??
? ? public DistributedIdGenerator(long workerId, long datacenterId) {
? ? ? ? if (workerId > MAX_WORKER_ID || workerId < 0) {
? ? ? ? ? ? throw new IllegalArgumentException("workerId不合法");
? ? ? ? }
? ? ? ? if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
? ? ? ? ? ? throw new IllegalArgumentException("datacenterId不合法");
? ? ? ? }
? ? ? ? this.workerId = workerId;
? ? ? ? this.datacenterId = datacenterId;
? ? }
? ??
? ? public synchronized long nextId() {
? ? ? ? long timestamp = timeGen();
? ? ? ??
? ? ? ? if (timestamp < lastTimestamp) {
? ? ? ? ? ? throw new RuntimeException("時鐘回撥異常");
? ? ? ? }
? ? ? ??
? ? ? ? if (timestamp == lastTimestamp) {
? ? ? ? ? ? sequence = (sequence + 1) & SEQUENCE_MASK;
? ? ? ? ? ? if (sequence == 0) {
? ? ? ? ? ? ? ? timestamp = tilNextMillis(lastTimestamp);
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? sequence = 0L;
? ? ? ? }
? ? ? ??
? ? ? ? lastTimestamp = timestamp;
? ? ? ??
? ? ? ? return ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT)
? ? ? ? ? ? ? ? | (datacenterId << DATACENTER_ID_SHIFT)
? ? ? ? ? ? ? ? | (workerId << WORKER_ID_SHIFT)
? ? ? ? ? ? ? ? | sequence;
? ? }
? ??
? ? private long tilNextMillis(long lastTimestamp) {
? ? ? ? long timestamp = timeGen();
? ? ? ? while (timestamp <= lastTimestamp) {
? ? ? ? ? ? timestamp = timeGen();
? ? ? ? }
? ? ? ? return timestamp;
? ? }
? ??
? ? private long timeGen() {
? ? ? ? return Instant.now().toEpochMilli();
? ? }
? ??
? ? /**
? ? ?* 將生成的ID轉換為訂單號
? ? ?*/
? ? public static String convertToOrderNo(long id) {
? ? ? ? return "ORD" + id;
? ? }
}

import java.time.Instant;/*** 分布式ID生成器(基于雪花算法改進)*/
public class DistributedIdGenerator {// 起始時間戳(2024-01-01)private final static long START_TIMESTAMP = 1704067200000L;// 機器ID所占位數private final static long WORKER_ID_BITS = 5L;// 數據中心ID所占位數private final static long DATACENTER_ID_BITS = 5L;// 序列號所占位數private final static long SEQUENCE_BITS = 12L;// 最大機器IDprivate final static long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);// 最大數據中心IDprivate final static long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);// 機器ID左移位數private final static long WORKER_ID_SHIFT = SEQUENCE_BITS;// 數據中心ID左移位數private final static long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;// 時間戳左移位數private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;// 序列號掩碼private final static long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);private final long workerId;private final long datacenterId;private long sequence = 0L;private long lastTimestamp = -1L;public DistributedIdGenerator(long workerId, long datacenterId) {if (workerId > MAX_WORKER_ID || workerId < 0) {throw new IllegalArgumentException("workerId不合法");}if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {throw new IllegalArgumentException("datacenterId不合法");}this.workerId = workerId;this.datacenterId = datacenterId;}public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException("時鐘回撥異常");}if (timestamp == lastTimestamp) {sequence = (sequence + 1) & SEQUENCE_MASK;if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT)| (datacenterId << DATACENTER_ID_SHIFT)| (workerId << WORKER_ID_SHIFT)| sequence;}private long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}private long timeGen() {return Instant.now().toEpochMilli();}/*** 將生成的ID轉換為訂單號*/public static String convertToOrderNo(long id) {return "ORD" + id;}
}

使用

// 修改日期格式
private static final String DATE_FORMAT = "yyyyMMddHHmmss";// 修改序列號長度
private static final int SERIAL_NUMBER_LENGTH = 4;// 修改訂單前綴
private static final String ORDER_PREFIX = "ORD";

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/80510.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80510.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/80510.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【嵌入式開發-SPI】

嵌入式開發-SPI ■ SPI簡介■ SPI &#xff08;Standard SPI&#xff09;■ DSPI &#xff08;Dual SPI&#xff09;■ QSPI是 Queued SPI的簡寫 ■ SPI簡介 SPI協議其實是包括&#xff1a;Standard SPI、Dual SPI和Queued SPI三種協議接口&#xff0c;分別對應3-wire, 4-wire…

基于HTTP頭部字段的SQL注入:SQLi-labs第17-20關

前置知識&#xff1a;HTTP頭部介紹 HTTP&#xff08;超文本傳輸協議&#xff09;頭部&#xff08;Headers&#xff09;是客戶端和服務器在通信時傳遞的元數據&#xff0c;用于控制請求和響應的行為、傳遞附加信息或定義內容類型等。它們分為請求頭&#xff08;Request Headers&…

基于Qt開發的http/https客戶端

成果展示&#xff1a; 使用Qt開發HTTP客戶端主要依賴QNetworkAccessManager、QNetworkRequest和QNetworkReply三大核心類。以下是具體實現要點及最佳實踐&#xff1a; 一、核心類與基礎流程?? 1.QNetworkAccessManager?? 作為HTTP請求的管理者&#xff0c;負責異步處理…

自適應蒙特卡洛定位-AMCL

自適應蒙特卡洛定位&#xff0c;簡稱AMCL&#xff0c;主要提供定位功能并以/tf形式輸出 蒙特卡洛算法的基本思想&#xff1a;當所要求的問題是某種事件出現的概率或者是某個變量的期望值時&#xff0c;它們可以通過某種"試驗"的方法&#xff0c;得到這種事件出現的概…

魯濱遜歸結原理詳解:期末考點+解題指南

1. 引言 歸結原理&#xff08;Resolution Principle&#xff09; 是自動定理證明和邏輯推理的核心技術&#xff0c;由約翰艾倫羅賓遜&#xff08;John Alan Robinson&#xff09;于1965年提出。它是一階謂詞邏輯的機械化推理方法&#xff0c;廣泛應用于人工智能&#xff08;如…

華為云Flexus+DeepSeek征文|DeepSeek-V3/R1商用服務開通教程以及模型體驗

在當今數字化浪潮迅猛推進的時代&#xff0c;云計算與人工智能技術的深度融合正不斷催生出眾多創新應用與服務&#xff0c;為企業和個人用戶帶來了前所未有的便利與發展機遇。本文將重點聚焦于在華為云這一行業領先的云計算平臺上&#xff0c;對 DeepSeek-V3/R1 商用服務展開的…

Matlab基于PSO-MVMD粒子群算法優化多元變分模態分解

Matlab基于PSO-MVMD粒子群算法優化多元變分模態分解 目錄 Matlab基于PSO-MVMD粒子群算法優化多元變分模態分解效果一覽基本介紹程序設計參考資料效果一覽 基本介紹 PSO-MVMD粒子群算法優化多元變分模態分解 可直接運行 分解效果好 適合作為創新點(Matlab完整源碼和數據),以包…

自然語言處理NLP中的連續詞袋(Continuous bag of words,CBOW)方法、優勢、作用和程序舉例

自然語言處理NLP中的連續詞袋&#xff08;Continuous bag of words&#xff0c;CBOW&#xff09;方法、優勢、作用和程序舉例 目錄 自然語言處理NLP中的連續詞袋&#xff08;Continuous bag of words&#xff0c;CBOW&#xff09;方法、優勢、作用和程序舉例一、連續詞袋( Cont…

商業模式解密:鳴鳴很忙下沉市場的隱憂,破局之路在何方?

文 | 大力財經 作者 | 魏力 在零售行業的版圖中&#xff0c;“鳴鳴很忙”憑借獨特的商業模式&#xff0c;在下沉市場異軍突起&#xff0c;成為不可忽視的力量。555億GMV、廣泛的縣域覆蓋以及高比例的鄉鎮門店&#xff0c;無疑彰顯了其在下沉市場的王者地位。然而&#xff0c;…

YOLOv5推理代碼解析

代碼如下 import cv2 import numpy as np import onnxruntime as ort import time import random# 畫一個檢測框 def plot_one_box(x, img, colorNone, labelNone, line_thicknessNone):"""description: 在圖像上繪制一個矩形框。param:x: 框的坐標 [x1, y1, x…

CATIA高效工作指南——常規配置篇(二)

一、結構樹&#xff08;Specification Tree&#xff09;操作技巧精講 結構樹是CATIA設計中記錄模型歷史與邏輯關系的核心模塊&#xff0c;其高效管理直接影響設計效率。本節從基礎操作到高級技巧進行系統梳理。 1.1 結構樹激活與移動 ??激活方式??&#xff1a; ??白線…

批量重命名bat

作為一名程序員&#xff0c;怎么可以自己一個個改文件名呢&#xff01; Windows的批量重命名會自動加上括號和空格&#xff0c;看著很不爽&#xff0c;寫一個bat處理吧&#xff01;?(ゝω???) 功能&#xff1a;將當前目錄下的所有文件名里面當括號和空格都去掉。 用法&…

嵌入式軟件開發常見warning之 warning: implicit declaration of function

文章目錄 &#x1f9e9; 1. C 編譯流程回顧&#xff08;背景&#xff09;&#x1f4cd; 2. 出現 warning 的具體階段&#xff1a;**編譯階段&#xff08;Compilation&#xff09;**&#x1f9ec; 2.1 詞法分析&#xff08;Lexical Analysis&#xff09;&#x1f332; 2.2 語法分…

【人工智能-agent】--Dify中MCP工具存數據到MySQL

本文記錄的工作如下&#xff1a; 自定義MCP工具&#xff0c;爬取我的鋼鐵網數據爬取的數據插值處理自定義MCP工具&#xff0c;把爬取到的數據&#xff08;str&#xff09;存入本地excel表格中自定義MCP工具&#xff0c;把爬取到的數據&#xff08;str&#xff09;存入本地MySQ…

Golang 應用的 CI/CD 與 K8S 自動化部署全流程指南

一、CI/CD 流程設計與工具選擇 1. 技術棧選擇 版本控制&#xff1a;Git&#xff08;推薦 GitHub/GitLab&#xff09;CI 工具&#xff1a;Jenkins/GitLab CI/GitHub Actions&#xff08;本文以 GitHub Actions 為例&#xff09;容器化&#xff1a;Docker Docker Compose制品庫…

網絡基礎1(應用層、傳輸層)

目錄 一、應用層 1.1 序列化和反序列化 1.2 HTTP協議 1.2.1 URL 1.2.2 HTTP協議格式 1.2.3 HTTP服務器示例 二、傳輸層 2.1 端口號 2.1.1 netstat 2.1.2 pidof 2.2 UDP協議 2.2.1 UDP的特點 2.2.2 基于UDP的應用層…

基于大模型預測的吉蘭 - 巴雷綜合征綜合診療方案研究報告大綱

目錄 一、引言(一)研究背景(二)研究目的與意義二、大模型預測吉蘭 - 巴雷綜合征的理論基礎與技術架構(一)大模型原理概述(二)技術架構設計三、術前預測與手術方案制定(一)術前預測內容(二)手術方案制定依據與策略四、術中監測與麻醉方案調整(一)術中監測指標與數…

【言語】刷題2

front&#xff1a;刷題1 ? 前對策的說理類 題干 新時代是轉型關口&#xff0c;要創新和開放&#xff08;前對策&#xff09;創新和開放不能一蹴而就&#xff0c;但是對于現代化很重要 BC片面&#xff0c;排除 A雖然表達出了創新和開放很重要&#xff0c;體現了現代化&#xf…

Blueprints - Gameplay Message Subsystem

一些學習筆記歸檔&#xff1b; Gameplay Message是C插件&#xff0c;安裝方式是把插件文件夾拷貝到Plugins中&#xff08;沒有的話需要新建該文件夾&#xff09;&#xff0c;然后再刷新源碼&#xff0c;運行項目&#xff1b; 安裝后還需要在插件中激活&#xff1a; 這樣&#…

火山云網站搭建

使用火山引擎的 **火山云&#xff08;Volcano Engine Cloud&#xff09;** 搭建網站&#xff0c;主要涉及云服務器、存儲、網絡等核心云服務的配置。以下是搭建網站的基本步驟和關鍵點&#xff1a; --- ### **一、準備工作** 1. **注冊火山引擎賬號** - 訪問火山引擎官網&…