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

Spring Boot JPA+MySQL使用Sequence生成主键出现负ID问题

异常原因
  • MySQL本身没有原生SEQUENCE序列对象,使用GenerationType.SEQUENCE策略时,Hibernate会自动用表模拟序列的方式生成主键,而非直接读取next_val字段值作为主键。
  • @SequenceGenerator注解未显式配置allocationSize参数时,该值默认是50。Hibernate默认采用块分配的优化策略生成ID,会一次性从序列表申请一段ID值供内存使用,减少表锁竞争。
  • 你设置的序列表初始值不符合块分配规则:默认50的块大小下,初始next_val需要至少为50才能生成正整数ID。初始值为0、1这类小于块大小的值时,ID计算逻辑会输出负数,和你遇到的初始值0生成-49、初始值1生成-48的现象完全吻合。
解决方法

根据业务场景选其中一种即可:

方案1:保留序列生成策略,修正配置

低并发场景(ID连续无跳号)

显式将allocationSize设为1,和单步生成的逻辑对齐,不会出现ID预分配:

  1. 修改实体类主键注解:
    @Id
    @Column(name = "TABLE_TYPE_ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "t_generator")
    @SequenceGenerator(
            name = "t_generator",
            sequenceName = "TABLE_SEQUENCE",
            initialValue = 1,
            allocationSize = 1 // 新增配置,指定步长为1
    )
    private Long tableTypeId;
    
  2. 重置序列表初始值:
    TRUNCATE TABLE TABLE_SEQUENCE;
    INSERT INTO TABLE_SEQUENCE VALUES(1);
    
    配置完成后ID会从1开始连续递增,无负数、无跳号。

高并发场景(性能优先)

保留默认50的块大小,减少序列表的读写锁竞争,只需要修正序列表初始值即可,不需要修改实体代码:

TRUNCATE TABLE TABLE_SEQUENCE;
INSERT INTO TABLE_SEQUENCE VALUES(50);

配置后ID从1开始生成,每消耗50个ID才会更新一次序列表,并发性能更好,ID可能存在不连续的情况(应用重启会跳过未使用的预分配ID段)。

方案2:改用MySQL原生自增主键(最适配MySQL)

MySQL原生支持AUTO_INCREMENT自增主键,不需要额外维护序列表,是MySQL场景下的最优选:

  1. 修改实体类主键策略:
    @Id
    @Column(name = "TABLE_TYPE_ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long tableTypeId;
    
  2. 给业务表的主键字段加自增属性,删除之前手动创建的TABLE_SEQUENCE表即可。
注意事项
  • 用表模拟序列时,必须保证代码中allocationSize的值和序列表的更新步长一致,否则会出现主键重复、ID异常跳变的问题。
  • 如果后续调整allocationSize的大小,序列表的next_val初始值也要对应调整为不小于allocationSize的值,避免再次出现负数ID。

内容的提问来源于stack exchange,提问作者Subhendu Mahanta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 04:54:24