雪花 ID 能从源头避免 sql 并发 插入主键冲突,因其是全局唯一、时间有序、无中心协调的 64 位整数,不依赖 数据库 自增或锁表;而自增主键在高并发下因写锁争抢易导致阻塞、重复或跳号,分布式 环境更失效;雪花 ID 由时间戳、机器 ID、序列号组成,只要机器 ID 唯一且时钟不回拨即绝对不冲突;应用层生成、无需 DB 参与、自带时序性、兼容主流数据库大 整型 ;落地需注意机器 ID 全局唯一、时钟回拨兜底、字段类型必须用 BIGint 或 DECIMAL(20,0);插入语句无需加锁或重试,冲突概率趋近于零。

用雪花 ID(Snowflake ID)做主键,能从源头避免 SQL 并发插入时的主键冲突,关键在于它生成的是全局唯一、时间有序、无中心协调的 64 位整数,不依赖数据库自增或锁表。
为什么 自增主键在并发下容易冲突
传统 AUTO_INCREMENT 依赖数据库写锁保证顺序,高并发插入时多个事务争抢同一自增值,轻则等待阻塞,重则因事务回滚或批量插入逻辑缺陷导致重复值或跳号;分布式环境下多个数据库实例更无法共享自增序列,直接失效。
雪花 ID 如何天然规避冲突
雪花 ID 由 4 部分组成:1 位符号位(固定 0)+ 41 位毫秒时间戳 + 10 位机器 ID(含 数据中心ID)+ 12 位序列号。同一毫秒内,靠机器 ID 和序列号组合确保不重复;不同毫秒天然错开。只要机器 ID 不重复、时钟不回拨,就绝对不冲突。
- 无需数据库参与 ID 生成,应用层直接产出,彻底脱离 DB 锁
- 时间戳前置,ID 本身自带时序性,适合做分库分表的 路由 键或查询排序
- 64 位整数,兼容 mysql BIGINT、postgresql BIGINT、oracle number(19) 等主流类型
落地时必须注意的 3 个细节
雪花 ID 不是“引入一个 SDK 就完事”,实际使用中这几个点常被忽略:
- 机器 ID 必须全局唯一 :不能所有服务实例都用默认值 0。建议通过配置中心分配,或结合 K8s StatefulSet 序号、consul 节点标签等方式动态生成
- 时钟回拨要兜底:如果服务器时间向后跳(如 NTP 校准),可能导致 ID 重复。生产环境需启用等待策略(如暂停生成直到追平时间)或降级为 UUID
- 数据库字段类型要匹配:别用 INT 或 UNSIGNED INT 存雪花 ID(最大只到 42 亿,而雪花 ID 可达 9 千亿),必须用 BIGINT(有符号)或 DECIMAL(20,0)
插入语句无需额外加锁或重试
因为 ID 已在应用层生成且唯一,SQL 插入变成标准的单条写入:
INSERT INTO order (id, user_id, amount) VALUES (912345678901234567, 1001, 99.9);
不用select … for UPDATE 查是否存在,不用 ON DUPLICATE KEY UPDATE,也不用 REPLACE INTO。冲突概率趋近于零,吞吐量直接受益于去中心化 ID 生成。