oracle自增id有3种实现方式:12c前用序列+触发器,12c起支持identity列(含always、by default、by default on null三种模式),以及应用层生成;identity列本质是隐式序列,更简洁可控。

Oracle 本身没有 AUTO_INCREMENT 或 IDENTITY(12c 之前)这种开箱即用的主键自增机制,必须靠 SEQUENCE + NEXTVAL 手动配合实现——但只要理解清楚触发时机和事务边界,它完全可靠,且比某些数据库的“伪自增”更可控。
创建 SEQUENCE 时必须显式指定 START WITH 和 INCREMENT BY
很多人直接写 CREATE SEQUENCE seq_id;,结果发现第一次 NEXTVAL 返回的是 1,但误以为是默认行为;其实 Oracle 的默认 START WITH 是 1、INCREMENT BY 是 1,但一旦表已有数据,或需要跳过某些值(比如兼容旧系统 ID),不显式声明极易出错。
实操建议:
-
START WITH必须 ≥ 当前表中最大 ID + 1,否则插入会报唯一约束冲突 - 如果主键列允许
NULL,而你又忘了在 INSERT 中调用NEXTVAL,就会意外存入NULL—— 建议主键列定义为NOT NULL - 避免使用
CACHE过大(如CACHE 1000),实例崩溃可能导致序列号“跳跃丢失”(不是重复,是跳号)
INSERT 语句中直接调用 seq.NEXTVAL 是最简方案
不需要触发器,也不需要先 SELECT seq.NEXTVAL INTO :v FROM DUAL 再插入——那只是多一次 round-trip,还容易在并发下引发竞争(除非加锁)。
正确写法就是:
INSERT INTO users (id, name) VALUES (user_seq.NEXTVAL, 'Alice');
常见错误现象:
- 写成
user_seq.CURRVAL:首次调用必报ORA-08002: sequence USER_SEQ.CURRVAL is not yet defined in this session - 在同一个 INSERT 里多次引用
NEXTVAL:每次调用都独立递增,比如(seq.NEXTVAL, seq.NEXTVAL)会导致两个不同值 - 把
NEXTVAL放在子查询或函数参数里(如TO_CHAR(seq.NEXTVAL)),仍会正常递增 —— 它不是“值”,是“运算”,只要被解析就生效
12c+ 推荐用 GENERATED ALWAYS AS IDENTITY 替代 SEQUENCE
如果你用的是 Oracle 12.1 及以上,IDENTITY 列本质是封装了 SEQUENCE + 隐式触发器,语法干净、语义明确,且支持 GENERATED BY DEFAULT ON NULL 这种兼容旧数据的模式。
对比差异:
-
IDENTITY列不能直接 UPDATE(会报ORA-30673: column is an identity column),而 SEQUENCE + 手动 INSERT 的字段可以随意更新 - 用
IDENTITY时,NEXTVAL/CURRVAL依然可用,但指向的是底层隐式序列,名字形如ISEQ$$_99999,不建议依赖 - 导出导入表结构时,
IDENTITY属性可能丢失(尤其用老旧 exp/imp),而显式 SEQUENCE + 触发器更易追踪和重建
真正容易被忽略的点:序列值只在 COMMIT 后对其他会话可见,但 NEXTVAL 本身不依赖事务——哪怕你 INSERT 后 ROLLBACK,那个序列号也已消耗,不会回退。这是设计使然,不是 bug。











