一、各方案的 Java 实现代码
- 数据库自增 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();
}
}
}
- 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
}
}
- 雪花算法(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);
}
}
}
- 业务自定义规则(可读性强)
结合业务信息生成唯一编号,比如订单号(业务标识 + 日期 + 随机数),适合需要人工识别的场景。
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 可读性要求,选择最贴合业务的方案。