oracle中@sequencegenerator必须显式指定sequencename且与已建序列名完全一致(含大小写),并配对使用@generatedvalue(strategy=sequence);allocationsize默认50会导致id跳号,需按需调整。
oracle 没有真正的自增主键,@sequencegenerator 是唯一靠谱的序列集成方式,但直接照搬 mysql 思路必踩坑。
为什么 @SequenceGenerator 在 Oracle 里不能只写名字
Oracle 序列必须显式创建,JPA 不会帮你建。只加 @SequenceGenerator(name = "my_seq") 而不指定 sequenceName,默认找叫 hibernate_sequence 的序列——而它通常不存在,启动就报 ORA-02289: sequence does not exist。
- 必须用
sequenceName明确指向已存在的 Oracle 序列名,比如@SequenceGenerator(name = "user_seq", sequenceName = "USER_ID_SEQ") -
name是 JPA 内部引用名,可任意;sequenceName必须和CREATE SEQUENCE USER_ID_SEQ中的名字完全一致(注意大小写,Oracle 默认大写) - 如果序列在非默认 schema 下,得写全名:
sequenceName = "SCHEMA_NAME.USER_ID_SEQ"
@GeneratedValue(strategy = GenerationType.SEQUENCE) 必须配对使用
只加 @SequenceGenerator 没用,主键字段上漏掉 @GeneratedValue,ID 就是 null;策略选错(比如写成 GenerationType.IDENTITY),Oracle 会直接抛异常,因为不支持 identity 列。
- 必须同时存在:类上的
@SequenceGenerator和字段上的@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "xxx") -
generator值必须和@SequenceGenerator.name完全匹配 - Oracle 不支持
GenerationType.IDENTITY或GenerationType.AUTO(后者在 Hibernate 5.4+ 里默认 fallback 到SEQUENCE,但行为不可控,别依赖)
性能陷阱:默认 allocationSize = 50 导致 ID 跳号
Oracle 序列本身是连续的,但 Hibernate 默认预取 50 个值缓存到内存。一旦应用重启、事务回滚或服务宕机,这 50 个里没用完的就永远丢失,造成 ID 不连续——不是 bug,是设计如此,但业务若校验“ID 必须严格递增”,这里就会出问题。
- 想严格连续,把
allocationSize = 1,但会显著增加数据库 round-trip 次数 - 更平衡的做法是设为
allocationSize = 10或20,兼顾性能与跳号容忍度 - 别改
initialValue或schema等参数,除非你真清楚它们在 Oracle 下如何映射
实体定义和 Sequence 创建要对齐
很多人先写好实体再建表建序列,结果序列 increment、start with 和实体期望不一致,插入时报 ORA-08004: sequence USER_ID_SEQ.NEXTVAL exceeds MAXVALUE 或初始 ID 对不上。
- 建议先在 Oracle 手动建序列:
CREATE SEQUENCE USER_ID_SEQ START WITH 1 INCREMENT BY 1 NOMAXVALUE NOCACHE; -
NOCACHE避免重启后跳号(但牺牲性能),生产环境常用CACHE 20,和 JPA 的allocationSize对齐 - 实体中
@Id @GeneratedValue(generator = "user_seq")的 generator 名,必须和@SequenceGenerator(name = "user_seq")一致,大小写敏感
最常被忽略的是 schema 权限和大小写——Oracle 里 user_id_seq 和 USER_ID_SEQ 是两个东西,而序列不在当前用户 schema 下时,光靠 sequenceName 写对还不够,得确认连接用户有 SELECT 权限。










