You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL SERIAL在单插入语句中是否保证无间隙?并发ID是否连续?

并发多记录插入时,自增ID能保证连续吗?

这个问题问到点子上了——在高并发场景下,自增ID的连续性经常是业务里容易踩坑的点,咱们得结合不同数据库的具体实现来拆解:

首先直接给你一个核心结论:绝大多数主流数据库的默认配置下,你没法保证单条语句插入的X条记录ID是严格连续的A到A+X-1,甚至会出现你担心的「其他线程插的ID夹在你的批次中间」的情况,不过你说的「线程1占A+100、线程2占A+99」这种倒序情况几乎不会发生,因为自增ID本质是全局递增的,只是并发分配会打乱批次内的连续性。

接下来分数据库细说:

MySQL(InnoDB引擎)

MySQL的自增ID机制和innodb_autoinc_lock_mode这个参数密切相关:

  • 默认配置(innodb_autoinc_lock_mode=1):对于「可预测行数的批量插入」(比如明确写了INSERT ... VALUES (...), (...), ...共X条),数据库会一次性提前分配好X个连续的自增ID给这条语句,这时候不管其他线程怎么并发插入,你的这X条记录的ID肯定是连续的——因为分配ID的操作是原子性的,不会被打断。但如果是「不可预测行数的插入」(比如INSERT ... SELECT或者LOAD DATA),数据库会用逐行分配ID的方式,这时候其他线程的插入就会插进来,导致你的ID不连续。
  • 并发模式(innodb_autoinc_lock_mode=2):这个模式下锁粒度更细,为了提升并发性能,即使是可预测行数的批量插入,也会逐行分配ID,这时候其他线程的插入就会打断你的ID连续性,你的X条记录ID可能会夹杂其他线程的ID。

PostgreSQL(SERIAL/BIGSERIAL)

PostgreSQL的自增ID是靠独立的「序列(Sequence)」实现的,每次插入记录时会调用nextval()获取下一个序列值。这里的关键是:nextval()是全局原子操作,但单条语句插入多条记录时,会多次调用nextval(),而这些调用之间是可以被其他线程的nextval()插进来的。

举个例子:你用单条语句插入10条记录,刚获取到第1个ID(比如100),另一个线程的插入语句也获取了ID101,然后你的语句继续获取ID102,结果你的10条记录ID就是100、102、103...中间夹了一个其他线程的101,完全没法保证连续。

另外,PostgreSQL的序列默认有缓存(CACHE参数),如果数据库重启,缓存里未使用的序列值会丢失,就算没有并发也可能出现ID断号的情况。

通用建议

不管用哪种数据库,我都强烈建议你不要依赖自增ID的连续性来实现业务逻辑:

  • 自增ID的设计初衷是给每条记录一个唯一标识,不是用来做连续编号的;
  • 并发、数据库重启、事务回滚(比如插入后回滚,ID不会回退)都会导致ID断号;
  • 如果业务需要连续的编号,最好单独维护一个编号生成器(比如用单独的表存当前编号,加锁获取),不要和数据库自增ID绑定。

内容的提问来源于stack exchange,提问作者Robert Pankowecki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:08:02