数据库id生成方案

数据库主键(id)的生成方案在设计系统时非常关键,既影响性能,也影响分布式扩展能力。

下面给出 5 种主流方案,并结合 Spring Boot + MyBatis + MySQL 项目,推荐最佳实践及示例代码。


🧩 一、常见主键生成方案对比

方案类型 示例 优点 缺点 适用场景
1. 自增主键(AUTO_INCREMENT) id BIGINT AUTO_INCREMENT 简单、易用、顺序性好 分布式环境易冲突、插入热点 单节点系统、小型项目
2. UUID(字符串) id CHAR(36) 全局唯一 查询慢、存储冗余大 无需排序的全局唯一标识
3. 雪花算法(Snowflake ID) long id = Snowflake.nextId(); 高性能、趋势递增 实现复杂、时间依赖 分布式系统
4. Redis / 数据库序列号 从 Redis 或 DB 获取自增号 全局唯一、可控 有外部依赖 多系统共享ID
5. 自定义混合ID(时间戳 + 随机数) 例如 20251025142312345 可读性好 可能重复(需控制) 临时或日志型记录

✅ 二、推荐方案(Spring Boot + MyBatis + MySQL)

建议使用:

雪花算法(Snowflake ID) + MyBatis 自动生成主键

这样既:

  • 不依赖 MySQL 自增(可分库分表);
  • 不会发生 ID 冲突;
  • 效率极高;
  • ID 可作为时间序列排序。

✅ 三、实现方案(雪花算法版本)

1️⃣ 新建工具类 SnowflakeIdGenerator.java

java 复制代码
package com.example.qrcode.util;

/**
 * 雪花算法ID生成器
 * 64位ID结构如下:
 * 1bit 符号位 + 41bit 时间戳 + 10bit 机器ID + 12bit 序列号
 */
public class SnowflakeIdGenerator {
    // 起始时间戳(自定义纪元)
    private static final long START_STAMP = 1672531200000L; // 2023-01-01

    // 每部分占位
    private static final long SEQUENCE_BIT = 12; // 序列号占12位
    private static final long MACHINE_BIT = 10;  // 机器ID占10位

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

    // 偏移量
    private static final long MACHINE_LEFT = SEQUENCE_BIT;
    private static final long TIMESTAMP_LEFT = SEQUENCE_BIT + MACHINE_BIT;

    private long machineId;  // 机器ID
    private long sequence = 0L;
    private long lastStamp = -1L;

    public SnowflakeIdGenerator(long machineId) {
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("机器ID超出范围");
        }
        this.machineId = machineId;
    }

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

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

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

        lastStamp = currStamp;

        return (currStamp - START_STAMP) << TIMESTAMP_LEFT // 时间部分
                | (machineId << MACHINE_LEFT)              // 机器部分
                | sequence;                                // 序列部分
    }

    private long waitNextMillis(long currStamp) {
        while (currStamp <= lastStamp) {
            currStamp = System.currentTimeMillis();
        }
        return currStamp;
    }
}

2️⃣ 在 Service 中使用

ini 复制代码
package com.example.qrcode.service;

import com.example.qrcode.entity.QrCodeRecord;
import com.example.qrcode.mapper.QrCodeMapper;
import com.example.qrcode.util.QrCodeUtil;
import com.example.qrcode.util.SnowflakeIdGenerator;
import org.springframework.stereotype.Service;

@Service
public class QrCodeService {

    private final QrCodeMapper qrCodeMapper;
    private final SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1L);

    public QrCodeService(QrCodeMapper qrCodeMapper) {
        this.qrCodeMapper = qrCodeMapper;
    }

    public QrCodeRecord createAndSave(String content) throws Exception {
        byte[] imageBytes = QrCodeUtil.generateQrAsBytes(content, 300, 300);

        QrCodeRecord record = new QrCodeRecord();
        record.setId(idGenerator.nextId());
        record.setContent(content);
        record.setImage(imageBytes);

        qrCodeMapper.insert(record);
        return record;
    }
}

3️⃣ 数据库表中改为手动ID插入

sql 复制代码
CREATE TABLE qr_code_record (
    id BIGINT PRIMARY KEY COMMENT '雪花算法ID',
    content VARCHAR(500) NOT NULL,
    image LONGBLOB NOT NULL,
    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

✅ 四、其他备选方案(简略)

🚀 1. MySQL 自增主键

sql 复制代码
id BIGINT PRIMARY KEY AUTO_INCREMENT

简单直接,适合单机。


🚀 2. UUID 方案

less 复制代码
record.setId(UUID.randomUUID().toString());

表结构:

scss 复制代码
id CHAR(36) PRIMARY KEY

但效率不如 Long 型。


🚀 3. Redis 全局序列号

ini 复制代码
Long id = redisTemplate.opsForValue().increment("global:qr:id");

✅ 五、推荐结论

场景 推荐方案
单体应用、小项目 AUTO_INCREMENT
分布式系统、微服务 雪花算法 (Snowflake)
跨系统全局唯一ID Redis 序列 或 UUID
临时或可读性强 ID 时间戳 + 随机数拼接
相关推荐
q***04051 小时前
在 Ubuntu 上安装 MySQL 的详细指南
mysql·ubuntu·adb
q***92514 小时前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
m0_639817155 小时前
基于springboot火锅店管理系统【带源码和文档】
java·spring boot·后端
赵渝强老师5 小时前
【赵渝强老师】MySQL集群解决方案
数据库·mysql
会编程的林俊杰6 小时前
SpringBoot项目启动时的依赖处理
java·spring boot·后端
码事漫谈6 小时前
C++循环结构探微:深入理解while与do...while
后端
李慕婉学姐6 小时前
【开题答辩过程】以《Javaweb的火花流浪动物救助系统设计与实现》为例,不会开题答辩的可以进来看看
vue.js·spring boot·mysql
百***62856 小时前
MySQL 常用 SQL 语句大全
数据库·sql·mysql
百***6976 小时前
MySQL数据库(SQL分类)
数据库·sql·mysql
码事漫谈6 小时前
现代C++:一场静默的革命,告别“C with Classes”
后端