oracle旧版本不支持auto_increment,需用sequence+trigger模拟自增主键;创建sequence须设对start with、increment by 1和nocache/cache;触发器须加for each row且判断:new.id is null;显式指定id会浪费序号但不跳号。

Oracle里为什么不能直接用AUTO_INCREMENT
因为Oracle原生不支持AUTO_INCREMENT或IDENTITY(直到12c才引入IDENTITY列,但老系统普遍还在用Sequence+Trigger方案)。如果你在11g或更早版本建表,或者需要兼容多版本环境,就必须手动配SEQUENCE和TRIGGER来模拟自增主键。
创建Sequence时要注意的三个关键参数
Sequence不是建完就能用,常见错误是没设好起始值、步长或缓存,导致插入时报错或跳号:
-
START WITH要和表中现有最大ID对齐(比如已有ID=100,就设START WITH 101) -
INCREMENT BY 1必须显式写上,避免误设成其他值 -
NOCACHE更安全(尤其在RAC环境),否则实例重启或异常可能丢号;若追求性能可设CACHE 20,但得接受小概率跳号
示例:
CREATE SEQUENCE emp_id_seq START WITH 1001 INCREMENT BY 1 NOCACHE;
BEFORE INSERT触发器里最容易漏掉的两件事
很多同学写了触发器却还是报ORA-01400: cannot insert NULL,问题往往出在这儿:
- 没加
FOR EACH ROW——少了这句,触发器不会对每一行生效 - 没判断
:NEW.id IS NULL——如果应用层偶尔传了ID,不该覆盖;只在为空时才赋值
正确写法:
CREATE OR REPLACE TRIGGER emp_id_trg
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
SELECT emp_id_seq.NEXTVAL INTO :NEW.id FROM DUAL;
END IF;
END;
INSERT时显式指定ID会导致Sequence跳号吗
不会跳号,但会“浪费”一个号。比如Sequence当前值是105,你INSERT时写了id = 100,下一次NEXTVAL还是返回106——Sequence自己不感知业务是否用了它。所以:
- 如果业务要求严格连续(如财务单据号),就不能依赖Sequence做“绝对唯一且连续”的ID,得用应用层控制
- 如果只是主键唯一性需求,跳号完全可接受,Oracle官方也明确说明Sequence不保证连续
- 测试时别用
SELECT seq.CURRVAL查刚插进去的ID,得用RETURNING INTO或单独查,否则可能读到别的会话刚取走的值
真正难处理的是并发插入+异常回滚后的间隙,这不是触发器能解决的,得接受这是Sequence机制本身的特性。











