平台唯一编号实现方案

一、各方案的 Java 实现代码

  1. 数据库自增 ID(MySQL + Java)
    这是最基础的方案,依赖 MySQL 的自增主键特性,Java 通过 JDBC 插入数据后获取自增 ID。
    前置条件:
    确保项目中引入 MySQL 驱动依赖(以 Maven 为例):
xml 复制代码
<!-- pom.xml 中添加MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
    <scope>runtime</scope>
</dependency>

Java 代码示例:

java 复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class AutoIncrementIdDemo {
    // 数据库连接配置
    private static final String URL = "jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true";
    private static final String USER = "root";
    private static final String PASSWORD = "your_password";

    public static void main(String[] args) {
        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {
            // 插入数据并获取自增ID(关键:Statement.RETURN_GENERATED_KEYS)
            String sql = "INSERT INTO users (username) VALUES (?)";
            PreparedStatement pstmt = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
            
            // 设置参数
            pstmt.setString(1, "zhangsan");
            // 执行插入
            pstmt.executeUpdate();
            
            // 获取自增的唯一ID
            ResultSet rs = pstmt.getGeneratedKeys();
            if (rs.next()) {
                long userId = rs.getLong(1);
                System.out.println("生成的用户唯一ID:" + userId); // 输出示例:1、2、3...
            }
            
            rs.close();
            pstmt.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. UUID/GUID(无中心化,全球唯一)
    Java 自带java.util.UUID类,可直接生成全球唯一的 UUID,无需额外依赖。
    Java 代码示例:
java 复制代码
import java.util.UUID;

public class UUIDDemo {
    public static void main(String[] args) {
        // 生成标准UUID(随机生成,UUID.randomUUID()等价于UUID4)
        UUID uuid = UUID.randomUUID();
        String standardUuid = uuid.toString();
        // 去掉横线的简洁版UUID
        String simpleUuid = standardUuid.replace("-", "");
        
        System.out.println("UUID(带横线):" + standardUuid); 
        // 输出示例:550e8400-e29b-41d4-a716-446655440000
        System.out.println("UUID(纯字符串):" + simpleUuid);
        // 输出示例:550e8400e29b41d4a716446655440000

        // 生成短UUID(可选,需引入第三方库)
        // Maven依赖:
        // <dependency>
        //     <groupId>com.github.stevenchen</groupId>
        //     <artifactId>shortuuid</artifactId>
        //     <version>1.0.1</version>
        // </dependency>
        // String shortUuid = ShortUUID.generate();
        // System.out.println("短UUID:" + shortUuid); // 输出示例:7W9X7a8s9k78a9d7
    }
}
  1. 雪花算法(Snowflake,分布式高可用)
    这是分布式高并发场景的首选方案,以下是线程安全的 Java 实现,可直接用于生产环境。
    Java 代码示例:
java 复制代码
public class SnowflakeIdGenerator {
    // ====================== 配置项 ======================
    // 起始时间戳(建议设为系统上线时间,此处为2024-01-01 00:00:00)
    private final long twepoch = 1704067200000L;
    // 机器ID位数(5位,最多支持32台机器)
    private final long workerIdBits = 5L;
    // 数据中心ID位数(5位,最多支持32个数据中心)
    private final long datacenterIdBits = 5L;
    // 序列号位数(12位,同一毫秒内最多生成4096个ID)
    private final long sequenceBits = 12L;

    // ====================== 最大值计算 ======================
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits); // 31
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // 31
    private final long maxSequence = -1L ^ (-1L << sequenceBits); // 4095

    // ====================== 位移数 ======================
    private final long workerIdShift = sequenceBits;
    private final long datacenterIdShift = sequenceBits + workerIdBits;
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    // ====================== 运行时变量 ======================
    private final long workerId; // 机器ID
    private final long datacenterId; // 数据中心ID
    private long sequence = 0L; // 序列号
    private long lastTimestamp = -1L; // 上次生成ID的时间戳

    // 锁对象,保证线程安全
    private final Object lock = new Object();

    // 构造函数:校验机器ID和数据中心ID合法性
    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException("Worker ID 超出范围:0~" + maxWorkerId);
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException("Datacenter ID 超出范围:0~" + maxDatacenterId);
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    // 获取下一个唯一ID
    public long nextId() {
        synchronized (lock) {
            long timestamp = System.currentTimeMillis();

            // 处理时钟回拨:时间戳小于上次生成ID的时间,说明时钟回拨,抛出异常
            if (timestamp < lastTimestamp) {
                throw new RuntimeException(
                        "时钟回拨异常!当前时间:" + timestamp + ",上次时间:" + lastTimestamp);
            }

            // 同一毫秒内,序列号自增
            if (timestamp == lastTimestamp) {
                sequence = (sequence + 1) & maxSequence;
                // 序列号用尽,等待下一毫秒
                if (sequence == 0) {
                    while (timestamp <= lastTimestamp) {
                        timestamp = System.currentTimeMillis();
                    }
                }
            } else {
                // 新毫秒,序列号重置为0
                sequence = 0L;
            }

            lastTimestamp = timestamp;

            // 拼接ID:按雪花算法结构组合各部分
            return ((timestamp - twepoch) << timestampLeftShift) // 时间戳部分
                    | (datacenterId << datacenterIdShift)       // 数据中心ID部分
                    | (workerId << workerIdShift)               // 机器ID部分
                    | sequence;                                 // 序列号部分
        }
    }

    // 测试示例
    public static void main(String[] args) {
        // 初始化生成器(workerId和datacenterId根据部署节点设置,避免重复)
        SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
        
        // 生成10个唯一ID
        for (int i = 0; i < 10; i++) {
            long id = generator.nextId();
            System.out.println("雪花算法ID:" + id);
        }
    }
}
  1. 业务自定义规则(可读性强)
    结合业务信息生成唯一编号,比如订单号(业务标识 + 日期 + 随机数),适合需要人工识别的场景。
    Java 代码示例:
java 复制代码
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

public class CustomBizIdGenerator {
    // 生成订单唯一编号:DD + 年月日时分秒 + 6位随机数
    public static String generateOrderId() {
        // 1. 生成日期部分(格式:20240115123045)
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String dateStr = sdf.format(new Date());
        
        // 2. 生成6位随机数(避免同一秒重复)
        Random random = new Random();
        int randomNum = 100000 + random.nextInt(900000); // 100000~999999
        String randomStr = String.valueOf(randomNum);
        
        // 3. 拼接:DD代表电商订单(可自定义,如WD代表物流单)
        return "DD" + dateStr + randomStr;
    }

    // 测试示例
    public static void main(String[] args) {
        String orderId = generateOrderId();
        System.out.println("自定义订单编号:" + orderId);
        // 输出示例:DD20240115123045123456
    }
}

总结

数据库自增 ID:Java 中通过PreparedStatement.RETURN_GENERATED_KEYS获取自增 ID,适合单库小型系统。

UUID:直接使用UUID.randomUUID()生成,无需依赖第三方,适合分布式非核心 ID 场景。

雪花算法:Java 实现需保证线程安全(用synchronized锁),处理时钟回拨问题,是高并发分布式系统核心 ID 的首选。

业务自定义规则:通过SimpleDateFormat生成日期、Random生成随机数,兼顾可读性和唯一性,适合订单号等场景。

核心选择原则:根据系统规模(单库 / 分布式)、并发量(低 / 高)、ID 可读性要求,选择最贴合业务的方案。

相关推荐
我是一只小青蛙8882 小时前
Java分层开发:PO、BO、DTO、VO全解析
java
步步为营DotNet2 小时前
深度剖析.NET 中CancellationToken:精准控制异步操作的关键
java·前端·.net
a努力。2 小时前
得物Java面试被问:B+树的分裂合并和范围查询优化
java·开发语言·后端·b树·算法·面试·职场和发展
a程序小傲2 小时前
中国电网Java面试被问:Kafka Consumer的Rebalance机制和分区分配策略
java·服务器·开发语言·面试·职场和发展·kafka·github
lbb 小魔仙2 小时前
从零搭建 Spring Cloud 微服务项目:注册中心 + 网关 + 配置中心全流程
java·python·spring cloud·微服务
BHXDML2 小时前
Java 常用中间件体系化解析——从单体到分布式,从“能跑”到“可控、可扩展、可演进”
java·分布式·中间件
weixin199701080162 小时前
安家 GO item_area - 获取地区类列表数据接口对接全攻略:从入门到精通
java·数据库·golang
码出财富2 小时前
60万QPS下如何设计未读数系统
java·spring boot·spring cloud·java-ee
05大叔2 小时前
大事件Day04
java·开发语言