数据库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 时间戳 + 随机数拼接
相关推荐
喵个咪1 分钟前
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:深度解析 Wire 依赖注入集成实践
后端·go
回家路上绕了弯1 分钟前
代码的三大核心素养:如何同时兼顾可维护性、可扩展性、可测试性
分布式·后端
快手技术3 分钟前
入围AA总榜Top 10,Non-Reasoning Model榜单第一!KAT-Coder-Pro V1 新版本踏浪归来!
前端·后端·前端框架
小坏讲微服务4 分钟前
Spring Boot4.0整合RabbitMQ死信队列详解
java·spring boot·后端·rabbitmq·java-rabbitmq
苏三说技术6 分钟前
工作中最常用的6种缓存
后端
谈笑也风生14 分钟前
验证IP地址(三)
python·tcp/ip·mysql
tc&34 分钟前
Kamailio SIP脚本编程核心概念总结
后端·kamailio
考虑考虑35 分钟前
maven项目使用指定JDK版本打包
java·后端·maven
大学生资源网42 分钟前
java毕业设计之中学信息技术课程教学网站的设计与实现源代码(源码+文档)
java·mysql·毕业设计·源码·springboot
咕白m6251 小时前
使用 C# 设置 Word 段落对齐样式
后端·c#