Oracle 12c+ 使用 GENERATED ALWAYS AS IDENTITY 实现自增主键,自动绑定序列且禁止手动插入(除非 OVERRIDING SYSTEM VALUE);11g 及以前需 SEQUENCE + TRIGGER 模拟,并注意触发器条件与并发安全。
oracle 12c 之后才能用 identity 实现真正意义上的自增主键;之前版本必须靠序列(sequence)+ 触发器(trigger)组合模拟,且不能叫“自增列”——那是 mysql/postgresql 的说法,oracle 没这概念。
怎么在 Oracle 12c+ 中创建带自增主键的表
直接用 GENERATED ALWAYS AS IDENTITY,这是最接近“自增列”的语法。它会自动绑定序列、禁止手动插入值(除非显式指定 OVERRIDING SYSTEM VALUE)。
常见错误现象:ORA-32795: cannot insert into a generated always identity column —— 这说明你试图往 IDENTITY 列里插值,但没加覆盖声明。
- 建表时写法:
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY - 如果想允许手动插入(比如迁移旧数据),改用:
GENERATED BY DEFAULT AS IDENTITY - 起始值和步长可指定:
GENERATED ALWAYS AS IDENTITY (START WITH 100 INCREMENT BY 5) - 注意:
GENERATED BY DEFAULT ON NULL是另一套逻辑(配合DEFAULT),不是自增,别混用
Oracle 11g 或更早版本怎么模拟自增主键
没有 IDENTITY,只能靠 SEQUENCE + TRIGGER 组合。这不是语法糖,是硬编码逻辑,所有插入路径都得走触发器,否则主键会空或重复。
使用场景:老系统升级前、中间件不支持 12c+ 语法、DBA 锁死版本策略。
- 先建序列:
CREATE SEQUENCE my_seq START WITH 1 INCREMENT BY 1 - 再建触发器:
BEFORE INSERT ON my_table FOR EACH ROW WHEN (new.id IS NULL) BEGIN :new.id := my_seq.NEXTVAL; END; - 务必加
WHEN (new.id IS NULL)条件,否则更新时也可能误赋新值 - 触发器里别用
CURRENT_VALUE,它不保证并发安全;只用NEXTVAL
用 SQL Developer 或 PL/SQL Developer 可视化建表时的坑
图形界面看似能勾选“Identity Column”,但它生成的 DDL 可能不兼容目标库版本,尤其导出到低版本环境时会直接报错。
性能影响:可视化工具常默认建 GENERATED BY DEFAULT AS IDENTITY,看起来灵活,但每次插入都要查序列缓存状态,比 ALWAYS 多一次判断开销。
- 导出 DDL 前,先确认右下角显示的数据库版本号是否和目标环境一致
- 勾选“Identity”后,手动检查生成的语句里有没有
START WITH和INCREMENT BY—— 图形界面有时会漏掉,默认值未必符合业务要求 - 不要依赖“自动填充主键”这种提示,那只是 IDE 的本地推测,不反映真实 DB 行为
最关键的是:Oracle 的“自增”从来不是列属性本身的能力,而是由序列对象 + 插入逻辑共同实现的。哪怕用了 IDENTITY,背后仍是序列;一旦删了关联序列(DROP SEQUENCE),表就废了。这点和 PostgreSQL 的 SERIAL 本质不同,别凭经验类推。










