IDENTITY列的核心价值是将主键生成权收归数据库层,GENERATED ALWAYS AS IDENTITY强制数据库接管并禁止显式插入,而BY DEFAULT ON NULL则提供兼容灵活性。

IDENTITY列本身不参与存储过程逻辑,它不简化存储过程,而是**替代掉原本需要在存储过程中手动调用序列+赋值的那部分代码**。如果你还在存储过程里写 NEXTVAL 或拼 INSERT INTO ... VALUES (seq_name.NEXTVAL, ...),说明你没真正用上 IDENTITY 的价值。
GENERATED ALWAYS AS IDENTITY 才能彻底甩开存储过程干预
只有 GENERATED ALWAYS AS IDENTITY 模式下,数据库才强制接管该列的值生成,任何显式插入(包括在存储过程中硬编码或拼接数值)都会报 ORA-32795 错误。这意味着:你不用再在存储过程中操心主键怎么来,直接 INSERT 就行。
- 建表时必须明确指定
GENERATED ALWAYS AS IDENTITY,不能只写AS IDENTITY(那是默认BY DEFAULT) - 存储过程里 INSERT 语句中,必须把该列从列名列表和 VALUES 列表中完全去掉,否则触发报错
- 如果业务逻辑中某些分支需要“带ID插入”(比如从其他系统同步数据),
ALWAYS模式就不适用——它不是“简化”,而是“禁止”
GENERATED BY DEFAULT ON NULL 是最接近传统习惯的折中选择
这种模式允许你在存储过程中显式传入主键值(比如做数据迁移、补录),但当传入 NULL 时,自动 fallback 到序列生成。它保留了灵活性,又避免了总要写 COALESCE(id, seq.NEXTVAL) 这类逻辑。
- INSERT 语句中可写
id列,值为NULL或具体数字;为NULL时由 Oracle 自动填充 - 注意:ORM 框架(如 MyBatis)若默认把未赋值字段设为
NULL,会自动触发序列,但若设成0或空字符串,则不会触发,可能造成重复主键 - 隐式序列的缓存大小(
CACHE)会影响高并发插入时的性能,建议根据吞吐量调到CACHE 20或更高,避免频繁回写磁盘
ALTER TABLE 添加 IDENTITY 列时不能直接加到已有主键列上
如果表已有主键且是普通 NUMBER 列,想改造成 IDENTITY,不能直接 ALTER TABLE ... MODIFY col GENERATED ALWAYS AS IDENTITY——Oracle 不支持对已有列添加 IDENTITY 属性。
- 必须新增一列(如
id_new)定义为GENERATED ALWAYS AS IDENTITY,再用UPDATE把旧值迁过去(注意顺序和事务隔离) - 之后用
ALTER TABLE ... DROP PRIMARY KEY+ALTER TABLE ... ADD PRIMARY KEY (id_new)切换主键 - 最后
ALTER TABLE ... DROP COLUMN id_old;整个过程需停写或加锁,大表慎操作
IDENTITY列的真正价值不在语法多简洁,而在于把主键生成权从应用层/存储过程层收归数据库层,并通过生成模式的选择,明确界定“谁能在什么条件下控制ID”。很多人踩坑,是因为把 BY DEFAULT 当成“安全默认”,却忽略了它不保证唯一性——只要应用层乱塞值,重复就来了。


















