Hibernate开启hibernate.id.new_generator_mappings=true删旧键后主键重复问题咨询
当hibernate.id.new_generator_mappings=true时,Hibernate使用的pooled优化器采用基于序列分段的ID分配逻辑:它从数据库序列获取当前值,以此为基准批量分配allocationSize个连续ID(比如序列当前为1、allocationSize=50时,分配1-50区间的ID)。
你遇到的负数ID及重复问题,本质是pooled优化器的计算逻辑在特定场景下的异常:当数据库存在已删除行,且Hibernate内部ID分配状态与数据库序列不同步时(比如应用重启后重新读取序列值、或有人手动调整过序列),优化器可能错误计算出负数ID段。由于Hibernate不会检查数据库中已存在的ID值,仅按自身分段逻辑生成,这些负数ID就会和未被删除的正数ID(如1、2等)重复。
另外,初始序列值为1时,pooled优化器的底层计算可能因序列增量与allocationSize的匹配问题,触发负数计算的bug——这是早期Hibernate版本中pooled优化器的已知问题。
hibernate.id.new_generator_mappings=false外) 切换到pooled-lo优化器:这是pooled的改进版本,采用「最后分配的ID + allocationSize」的方式计算下一批ID,不会出现负数问题。配置示例:
@Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "entity_seq") @SequenceGenerator(name = "entity_seq", allocationSize = 50, optimizer = "pooled-lo") private Long id;同时确保数据库序列的
INCREMENT BY值等于allocationSize,初始值设为1。显式配置序列生成器:不依赖
GenerationType.AUTO自动推断,手动指定序列参数,确保Hibernate与数据库序列完全同步:@Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "entity_seq") @SequenceGenerator( name = "entity_seq", sequenceName = "ENTITY_SEQ", initialValue = 1, allocationSize = 50 ) private Long id;并在数据库中创建对应序列,设置
INCREMENT BY 50,避免双方计算偏差。改用TABLE生成策略:通过数据库表管理ID分配的当前值,虽性能略低于序列,但稳定性更高,不会出现负数ID问题:
@Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "entity_table") @TableGenerator( name = "entity_table", table = "ID_GENERATOR", pkColumnName = "ENTITY_TYPE", valueColumnName = "NEXT_ID", allocationSize = 50 ) private Long id;接受ID间隙,避免手动干预序列:主键核心要求是唯一而非连续,删除行后不要手动修改序列值,让Hibernate按pooled优化器逻辑继续分配后续ID,即使存在间隙也不会导致重复。
内容的提问来源于stack exchange,提问作者Vijay05

