电商订单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版本(类似抖音订单号)

相关推荐
梦梦代码精40 分钟前
电商系统不是技术堆叠:LikeShop如何用分层Hold住复杂业务?
java·docker·代码规范
负责的蛋挞1 小时前
异步HttpModule的实现方式
java·服务器·前端
AC赳赳老秦1 小时前
防火墙规则批量配置实战:OpenClaw 自动生成模板、批量下发与合规性校验全解析
java·开发语言·人工智能·python·github·php·openclaw
Tian_Hang1 小时前
Eclipse Ditto 物模型相关代码
java·运维·服务器·ide·eureka·eclipse
Mr-Wanter2 小时前
wsl2 jdk管理工具之sdkman
java·开发语言·sdkman
唐青枫3 小时前
Java Future 与 CompletableFuture 实战指南:从异步结果到任务编排
java
长孙豪翔3 小时前
在.net中读写config文件的各种方法
java·数据库·.net
tachibana23 小时前
hot100 回文链表(234)
java·网络·数据结构·leetcode·链表
可乐ea3 小时前
【Java八股|第10篇】Java 中的包装类和自动拆装箱
java·面试题·包装类·java八股
zfoo-framework3 小时前
mongo最佳实战(from mongo中文社区)
java