主键冲突本质是sequence值与表中最大id脱节,非sequence故障;需先查max(id)和currval确认脱节,再用increment by+nextval+重置步进方式同步,且hibernate须设allocationsize=1并与序列步长一致。
主键冲突不是 sequence 坏了,而是 seq_name.nextval 返回的值在表里已经存在——根本原因是 sequence 当前状态和表中实际最大 id 脱节。
ORA-00001 报错时先确认是不是 Sequence 同步问题
别急着改代码。先连上数据库执行两行 SQL:
-
SELECT NVL(MAX(id), 0) FROM your_table;—— 查出表里当前最大 ID(比如是 123) -
SELECT your_seq.CURRVAL FROM DUAL;或SELECT your_seq.NEXTVAL FROM DUAL;—— 看 Sequence 当前值(比如 CURRVAL 是 98)
如果第二步结果 ≤ 第一步结果,就坐实了脱节:下一次 NEXTVAL 很可能返回已存在的 ID。
常见诱因包括:手动 INSERT 过固定 ID、清库没重置 Sequence、事务回滚后 NEXTVAL 已消耗、开发环境反复 DROP TABLE + CREATE TABLE 但 Sequence 没删。
@SequenceGenerator 必须配 allocationSize = 1
Hibernate 默认用 PooledOptimizer,会预取一批值(比如默认 allocationSize = 50),导致 Sequence 实际跳变远超表中 ID 增长节奏。你看到的“第一次正常,后面全乱”,大概率就是它在作怪。
实体类里必须显式写死:
@SequenceGenerator(name = "user_seq_gen", sequenceName = "USER_SEQ", allocationSize = 1)
不加这句,Hibernate 可能从 1 开始取,取完直接跳到 51,而你表里刚插到 10,中间空档一塌糊涂。
注意:allocationSize 必须和 Sequence 的 INCREMENT BY 值一致,否则 NEXTVAL 和 Hibernate 缓存对不上。
MyBatis 中 @SequenceGenerator 本身不生效
这个注解只是个标记,不会自动触发任何逻辑。真正干活的是 @SelectKey 或 XML 里的 <selectkey></selectkey>。
正确写法示例:
@Insert("INSERT INTO user (id, name) VALUES (#{id}, #{name})")<br>@SelectKey(statement = "SELECT USER_SEQ.NEXTVAL FROM DUAL", keyProperty = "id", before = true, resultType = long.class)<br>int insertUser(User user);
漏掉 before = true 或 resultType,或者 SQL 少了 FROM DUAL,ID 就是 null;用了 useGeneratedKeys = true 反而会绕过 Sequence,走 Oracle 不支持的 RETURNING,静默失败。
Spring Boot 启动时自动重置 Sequence 要分清环境
只适合本地或 CI 清库场景,生产绝对禁用。核心是在 JPA 建表完成、业务插入开始前执行三步 SQL:
-
ALTER SEQUENCE your_seq INCREMENT BY ?;(? = 表最大 ID + 1 − 当前 CURRVAL) -
SELECT your_seq.NEXTVAL FROM DUAL;(必须执行,否则不推进) -
ALTER SEQUENCE your_seq INCREMENT BY 1;(必须改回来,否则后续全崩)
用 JdbcTemplate 在 ApplicationRunner 里跑就行,但得确保它在 EntityManagerFactory 初始化之后、第一个 save() 之前运行——顺序错了,等于白干。
最易忽略的一点:Oracle 11g/10g 不支持 RESTART WITH,必须靠 INCREMENT BY 组合操作;而 12c+ 虽然支持,但老项目升级驱动不及时,照样 fallback 到旧逻辑。











