Spring Boot+Oracle 11g:JPA与触发器生成ID值不一致问题
解决JPA与Oracle触发器重复获取序列ID的问题
问题根源
当前代码中,JPA通过@GeneratedValue(strategy = GenerationType.SEQUENCE)主动调用序列BOOK_ENTRY_SEQ.nextval生成ID,而数据库插入前触发器BOOK_ENTRY_TRG又会再次调用nextval设置ID,导致两次取值,出现调试ID为61但数据库存储为62的情况。
解决方案
要让触发器单独负责ID生成,需修改实体类的ID字段配置,让JPA不再主动生成ID,转而依赖触发器,并在插入后同步数据库生成的ID。
修改BookEntry实体类的ID字段
将原ID字段的注解替换为以下配置:
@Id @Column(name = "ID", updatable = false, insertable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
如果Oracle 11g环境下GenerationType.IDENTITY不生效,可改用Hibernate专属注解:
@Id @Column(name = "ID", updatable = false, insertable = false) @Generated(GenerationTime.INSERT) private Long id;
配置说明
- 移除序列生成注解:删除
@SequenceGenerator和@GeneratedValue(strategy = GenerationType.SEQUENCE),避免JPA主动调用序列取值。 - insertable = false:确保JPA生成INSERT语句时不包含ID字段,给触发器留出设置ID的空间。
- 生成策略注解:
@GeneratedValue(strategy = GenerationType.IDENTITY)或@Generated(GenerationTime.INSERT)用于告知JPA,ID由数据库生成,插入操作完成后需要从数据库同步最新的ID值到实体对象。
验证效果
修改后调用save方法时:
- JPA生成的INSERT语句不包含ID字段;
- 触发器自动调用
BOOK_ENTRY_SEQ.nextval为ID赋值; - 插入完成后,JPA将数据库生成的ID同步回实体对象;
- 调试时看到的ID与数据库存储的ID完全一致,不会再出现跳号情况。
内容的提问来源于stack exchange,提问作者Daptal Ms
相关产品推荐
相关产品推荐

