导读:本期聚焦于剑客创作的《Oracle identity列怎么用?详解自增主键的多种实现方式》,敬请观看详情。Oracle数据库从12c版本开始引入了identity列,让自增主键的创建变得和MySQL一样简单,不再需要手动创建sequence序列和触发器配合使用。本文将系统讲解identity列的两种生成方式Always和By Default的区别,深入剖析其底层与sequence的关联原理,并对比传统sequence加触发器方案、12c之前的旧式做法,帮助读者根据实际业务场景选择合适的自增主键实现方案。文中还包含identity列的创建语法、插入数据时的注意事项、修改与删除自增列的操作示例,以及常见报错的原因分析和解决思路,适合Oracle开发者和数据库管理人员参考学习。

在Oracle 12c之前的版本中,想要实现自增主键,必须先创建一个sequence序列对象,再配合触发器在插入数据前自动获取序列值,写法繁琐且性能有损耗。从Oracle 12c开始,数据库原生支持identity列,只需在建表时加一个关键字,就能实现类似MySQL的自增效果,代码量大大减少,维护成本也随之降低。本文将围绕identity列的用法、底层原理以及与传统方案的对比展开详细说明。

Oracle identity列怎么用?详解自增主键的多种实现方式

一、identity列的基本语法与两种生成方式

identity列的语法在12c及以上版本中直接写在建表语句里,其标准形式如下:

CREATE TABLE t_user (
  id      NUMBER GENERATED AS IDENTITY PRIMARY KEY,
  name    VARCHAR2(50)
);

上面这条语句执行后,id列就成了自增列,插入数据时不需要显式指定id的值。identity列实际上分为两种生成方式,分别是GENERATED ALWAYS AS IDENTITYGENERATED BY DEFAULT AS IDENTITY,两者在使用上有明显区别。

第一种是Always方式,表示id的值永远由Oracle自动生成,如果插入语句中显式指定了id值,会直接报错ORA-32795错误。示例:

-- Always方式
CREATE TABLE t_user1 (
  id   NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name VARCHAR2(50)
);

INSERT INTO t_user1 (name) VALUES ('张三');  -- 成功
INSERT INTO t_user1 (id, name) VALUES (100, '李四');  -- 报错 ORA-32795

第二种是By Default方式,表示默认由Oracle自动生成,但也允许用户手动插入指定的值,灵活性更高。当表中已有数据迁移或需要手工补数据时,这种方式更实用。如果指定了START WITH和INCREMENT BY参数,还可以控制起始值和步长:

CREATE TABLE t_user2 (
  id   NUMBER GENERATED BY DEFAULT AS IDENTITY 
         (START WITH 1000 INCREMENT BY 1) PRIMARY KEY,
  name VARCHAR2(50)
);

INSERT INTO t_user2 (name) VALUES ('王五');   -- id为1000
INSERT INTO t_user2 (id, name) VALUES (5000, '赵六');  -- 手动指定,成功

需要注意的是,By Default方式手动插入值后,序列并不会自动跳过这个值,后续自动生成的id可能与手动插入的值冲突。如果希望手动插入时也能让序列感知并继续,可以使用GENERATED BY DEFAULT ON NULL AS IDENTITY,当插入NULL时依然走自增逻辑。

二、identity列的底层原理:其实是sequence的封装

identity列并不是凭空实现的自增机制,Oracle在内部会自动创建一个sequence对象来支撑它。查看数据字典可以发现,系统自动生成了一个以ISEQ$$_开头的序列:

SELECT sequence_name, last_number, increment_by
FROM user_sequences
WHERE sequence_name LIKE 'ISEQ$$_%';

这个内部序列对用户来说是隐藏管理的,不能直接修改它的属性。如果需要调整自增的起始值或步长,必须通过ALTER TABLE ... MODIFY语句来实现,例如:

ALTER TABLE t_user2 MODIFY
  (id GENERATED BY DEFAULT AS IDENTITY (START WITH 2000 INCREMENT BY 2));

此外,identity列的值在回滚或事务失败后同样会出现空洞。这是因为sequence本身是非事务性的,取出的值即使没有提交成功也不会归还,这是所有基于sequence方案共同的特点,业务设计时不能假设id完全连续。

由于identity列本质上依赖内部sequence,它的取值性能也和sequence的缓存机制相关。默认情况下identity列使用CACHE 20,在批量插入场景下性能表现良好。如果遇到RAC环境下的高并发插入,可以考虑增大缓存值以减少实例间争用,同样通过ALTER语句调整。

三、与传统sequence加触发器方案的对比

在12c之前,经典的实现方式是先建sequence,再建一个BEFORE INSERT触发器,代码如下:

CREATE SEQUENCE seq_user START WITH 1 INCREMENT BY 1;

CREATE OR REPLACE TRIGGER trg_user BEFORE INSERT ON t_user3
FOR EACH ROW
BEGIN
  SELECT seq_user.NEXTVAL INTO :new.id FROM dual;
END;
/
INSERT INTO t_user3 (name) VALUES ('测试');
SELECT seq_user.CURRVAL FROM dual;  -- 查询当前值

两种方案各有优劣。identity列的优势在于语法简洁、无需维护额外的触发器对象、可移植性思考更接近MySQL标准写法,迁移成本低;劣势是灵活性略差,无法在复杂场景下复用同一个序列。而传统方案的优势是sequence可以被多张表共享,触发器里还可以加入更复杂的逻辑,缺点是对象数量多、触发器在高并发插入时带来额外开销,且SQL语句不够直观。

还有第三种做法,即不使用触发器,而是在INSERT语句中直接写seq_user.NEXTVAL,从12c开始甚至可以省略FROM dual。这种方式介于两者之间,既保留了sequence的复用能力,又减少了触发器的性能损耗,是很多老系统持续使用的方案。

四、常见问题与注意事项

首先是版本兼容问题,identity列只支持Oracle 12c及以上版本,如果脚本需要在11g环境运行,建表语句会直接报语法错误,编写DDL时要注意目标库版本。

其次是删除和修改的限制。不能直接删除identity列上的自增属性以外的东西而不影响数据,若要去掉自增特性,可以执行ALTER TABLE t_user2 MODIFY (id DROP IDENTITY),此时列和数据的保留但不再自增。删除表时,内部的ISEQ$序列会随表一起自动清理,无需手工干预。

最后是数据迁移场景。如果从旧表迁移数据到带identity列的新表,建议使用By Default方式,先把旧数据连同id一起插入,再通过ALTER语句把START WITH调整到最大id之后,避免后续自增值与历史数据冲突。掌握这些细节,就能在实际项目中灵活运用identity列,写出更简洁高效的建表脚本。

Oracle identity列Oracle自增主键sequence序列修改时间:2026-08-31 15:00:55

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。