Hibernate SequenceGenerator插入超50条数据时出现ID重复异常
问题根本原因
你遇到的ID冲突问题是JPA序列生成器的allocationSize配置和数据库序列的步长配置不匹配导致的:
- JPA的
@SequenceGenerator注解默认allocationSize值为50,该参数的作用是:JPA每次从数据库查询一次序列当前值后,会在应用内存中连续分配allocationSize个ID,用完才会再次查询数据库序列。 - 你在Liquibase中配置的数据库序列步长
incrementBy="10",每次查询序列时只会比上次返回的值大10。
这就导致JPA以为自己拿到的起始值之后的50个ID都是独占可用的,但实际上数据库序列10个之后就会进入下一轮分配,第二次查询到的序列值会和之前JPA已经分配过的ID重复,就触发了主键冲突异常。
你观察到的几个现象完全符合这个逻辑:
- 应用生成ID每次自增1:这是JPA在内存中批量分配ID的正常表现,不需要每次生成ID都查询数据库
- 数据库手动查序列步长为10:和你Liquibase配置一致
- 固定保存第50个对象时报错:刚好是第一批分配的50个ID用完,JPA第二次查询数据库拿到的序列值已经被之前的分配覆盖,出现重复ID。插入数量少于50时第一批ID没用完,不会触发二次查询,因此不会报错。
解决方案
两边的步长配置对齐即可,有两种可选方案:
方案1:保持数据库序列配置不变,修改JPA注解
显式给@SequenceGenerator指定allocationSize = 10,和数据库步长一致:
public class Publication implements Serializable, Identifiable { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") @SequenceGenerator(name = "sequenceGenerator", allocationSize = 10) private Long id; }
方案2:保持JPA默认配置不变,修改数据库序列步长
把Liquibase中序列的incrementBy改成和JPA默认allocationSize一致的50:
<createSequence incrementBy="50" sequenceName="sequence_generator" startValue="1" cacheSize="10"/>
注意:修改配置前请先确认当前数据库序列的当前值,避免修改后生成的ID和已存在的业务数据主键冲突,生产环境操作前建议先备份数据。
内容的提问来源于stack exchange,提问作者Giacomo Voß
相关产品推荐
相关产品推荐

