电商订单id设计思路

文章目录

  • 前言
  • 一、核心思路
  • [二、Snowflake 算法实现(Java版)](#二、Snowflake 算法实现(Java版))
      • [1️⃣ Snowflake 工具类](#1️⃣ Snowflake 工具类)
  • [三、订单号生成 Service](#三、订单号生成 Service)
      • [2️⃣ 订单号生成器](#2️⃣ 订单号生成器)
  • [四、Controller 测试](#四、Controller 测试)
  • 五、生产环境必须注意(重点)
      • [✅ 1. machineId / datacenterId 不能乱写](#✅ 1. machineId / datacenterId 不能乱写)
      • [✅ 2. 时钟回拨问题](#✅ 2. 时钟回拨问题)
      • [✅ 3. 高并发优化](#✅ 3. 高并发优化)
      • [✅ 4. 是否需要"用户可读订单号"](#✅ 4. 是否需要“用户可读订单号”)
  • 六、总结(给你决策建议)

前言

在 Spring Boot 里实现「业务前缀 + Snowflake ID


一、核心思路

订单号结构:

js 复制代码
订单号 = 业务前缀 + Snowflake生成的ID

比如:

js 复制代码
OD + 1789237498127349823

或者更好一点(带时间可读):

js 复制代码
OD + yyyyMMdd + SnowflakeID

二、Snowflake 算法实现(Java版)

1️⃣ Snowflake 工具类

java 复制代码
@Component
public class SnowflakeIdGenerator {

    // 起始时间戳(自己定义)
    private final long START_TIMESTAMP = 1700000000000L;

    // 每部分占用位数
    private final long SEQUENCE_BIT = 12;   // 序列号
    private final long MACHINE_BIT = 5;     // 机器ID
    private final long DATACENTER_BIT = 5;  // 机房ID

    // 最大值
    private final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
    private final long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
    private final long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BIT);

    // 位移
    private final long MACHINE_LEFT = SEQUENCE_BIT;
    private final long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final long TIMESTAMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

    private long datacenterId;
    private long machineId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    public SnowflakeIdGenerator() {
        this(1, 1); // 默认机房ID=1,机器ID=1
    }

    public SnowflakeIdGenerator(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId非法");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId非法");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    public synchronized long nextId() {
        long currTimestamp = System.currentTimeMillis();

        if (currTimestamp < lastTimestamp) {
            throw new RuntimeException("时钟回拨,拒绝生成ID");
        }

        if (currTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0L) {
                currTimestamp = waitNextMillis();
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = currTimestamp;

        return (currTimestamp - START_TIMESTAMP) << TIMESTAMP_LEFT
                | datacenterId << DATACENTER_LEFT
                | machineId << MACHINE_LEFT
                | sequence;
    }

    private long waitNextMillis() {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}

三、订单号生成 Service

2️⃣ 订单号生成器

java 复制代码
@Service
public class OrderNoGenerator {

    @Autowired
    private SnowflakeIdGenerator snowflakeIdGenerator;

    public String generateOrderNo() {
        long id = snowflakeIdGenerator.nextId();

        String date = LocalDate.now()
                .format(DateTimeFormatter.ofPattern("yyyyMMdd"));

        return "OD" + date + id;
    }
}

四、Controller 测试

java 复制代码
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderNoGenerator orderNoGenerator;

    @GetMapping("/gen")
    public String genOrderNo() {
        return orderNoGenerator.generateOrderNo();
    }
}

访问:

js 复制代码
GET /order/gen

返回示例:

js 复制代码
OD202604271789237498127349823

五、生产环境必须注意(重点)

✅ 1. machineId / datacenterId 不能乱写

否则会重复

推荐:

  • 从配置中心获取
  • 或用 IP hash
  • 或用容器编号

✅ 2. 时钟回拨问题

解决方案:

  • NTP 时间同步
  • 或检测后等待(上面已处理)

✅ 3. 高并发优化

当前是 synchronized,可以:

  • 换成:

    • AtomicLong + CAS
    • 或直接用开源方案:

👉 更推荐:

  • 美团 Leaf
  • 百度 UidGenerator

✅ 4. 是否需要"用户可读订单号"

如果你要给用户看,建议:

js 复制代码
OD + 日期 + 随机码/短ID

否则 Snowflake 太长:

js 复制代码
OD202604271789237498127349823

可以优化成:

js 复制代码
OD2404278F3K92

六、总结(给你决策建议)

场景 推荐
小项目 时间戳 + Redis INCR
中大型电商 Snowflake
超高并发(亿级) Leaf / UidGenerator

后续可以升级成:

✅ 支持分库分表

✅ 支持多机房自动分配ID

✅ 可读订单号(防爬虫、防推测)

✅ 短ID版本(类似抖音订单号)

相关推荐
碳基硅坊12 小时前
Spring AI:把大模型接进 Spring 应用
java·人工智能·spring ai
黄毛火烧雪下13 小时前
Java 核心知识点总结(一)
java·开发语言
技术小结-李爽13 小时前
【工具】Maven的下载、安装、使用
java·maven
极创信息13 小时前
Linux挖矿病毒深度清理实战教程,从进程隐藏、Rootkit驻留到彻底根除
java·大数据·linux·运维·安全·tomcat·健康医疗
努力成为AK大王13 小时前
并发编程的核心挑战、优化方案与核心知识点总结
java·开发语言·数据库
云烟成雨TD13 小时前
Agent Scope Java 2.x 系列【10】技能(Skill)
java·人工智能·agent
摇滚侠13 小时前
SpringMVC 入门到实战 DispatcherServlet 源码解读 92-95
java·后端·spring·maven·intellij-idea
键盘歌唱家14 小时前
Spring AI 入门分享:它和“直接调 API“到底差在哪
java·人工智能·spring
宸丶一14 小时前
Day 10:LangGraph - Agent 的图执行引擎
java·windows·python
hikktn14 小时前
Excel 导出 OOM 预防实战:30 万行从堆溢出到 50MB 的演进
java·excel·easyexcel