首页 89游戏攻略 正文

oraclecreatesequence设置自增主键,实用技巧分享!

哥们儿最近搞项目,又碰上老问题了——数据库里那自增主键,每次都得琢磨怎么搞定。以前用别的数据库,大多有那种自带的IDENTITY属性,一设就完事儿。可咱用的是Oracle,这家伙就得有点自己的脾气和玩法。一开始也头疼,心想咋弄才能像其他数据库那样,插入数据时不用管主键,它自己就给我填上。

本站为89游戏官网游戏攻略分站,89游戏每日更新热门游戏,下载请前往主站地址:www.gm89.icu

琢磨了好几天,查了不少资料,也问了些前辈,才搞明白Oracle也有自己的套路,而且还挺灵活的,那就是用序列(Sequence)

我怎么一步步把自增主键搞定的

这事儿还得从头说起,我当时要建一个用户表,叫USER_INFO,里面肯定得有个用户ID作为主键。想达到自增的目的,我就决定分两步走:先创建一个序列,再把这个序列和我的表主键关联起来。

第一步:创建序列

我得给我的用户ID搞个自动生成器。这个生成器就是序列。当时我是这么敲命令的:

CREATE SEQUENCE USER_INFO_SEQ
START WITH 1
INCREMENT BY 1
NOMAXVALUE
NOCACHE
NOCYCLE;

这里面每一个参数,我当时都是有考量的。

  • CREATE SEQUENCE USER_INFO_SEQ:这句就是说,我要创建一个序列,名字叫USER_INFO_SEQ。这个名字我一般会和表名或者字段名有点关联,方便后面自己看着不糊涂。
  • START WITH 1:这个简单,就是让序列从1开始数。我的第一个用户ID就是1。
  • INCREMENT BY 1:每次自增1。也就是说,1后面是2,2后面是3,很符合自增主键的需求。
  • NOMAXVALUE:这个很重要,就是不设最大值。如果设了最大值,万一哪天数据量大了,序列跑完了就歇菜了,到时候还得手动修改,很麻烦。不设最大值,它就能一直数下去,除非数据库存不下。
  • NOCACHE:这个也是个小技巧。CACHE的意思是序列会预先生成一批号码放在内存里,下次需要的时候直接从内存拿,速度快。但问题是,如果数据库突然挂了或者重启,这些还没用出去的预存号码就丢了,下次再启动,序列会接着上次已经用过的最大值继续生成,这就导致中间ID有“断号”的情况。对普通数据没但对自增主键,我个人是喜欢它连续的,所以就用了NOCACHE,每次都去数据库里取新的,虽然慢一点点,但能保证ID的连贯性,没有断号的顾虑。
  • NOCYCLE:不循环。如果序列数到头了,不让它从头再来。这个和NOMAXVALUE是搭档,因为我压根就没设最大值,所以也不存在循环的问题。

第二步:把序列和表主键关联起来

序列建好了,它自己还不能给表的主键赋值。这就需要一个触发器(Trigger)来帮忙。

我先把我那用户表建起来:

CREATE TABLE USER_INFO (
USER_ID NUMBER(10) PRIMARY KEY,
USER_NAME VARCHAR2(100) NOT NULL,
EMAIL VARCHAR2(100)

注意看,USER_ID这里我没写什么AUTO_INCREMENT之类的,因为Oracle不支持那样直接写。它只是一个普通的NUMBER类型,并且是主键。

重头戏来了,就是写触发器。这个触发器会在每次有新数据插入USER_INFO表之前触发,然后把序列生成的下一个值赋给USER_ID

CREATE OR REPLACE TRIGGER TRG_USER_INFO_BI
BEFORE INSERT ON USER_INFO
FOR EACH ROW
BEGIN
SELECT USER_INFO_* INTO :*_ID FROM DUAL;
END;

我来解释下这个触发器:

  • CREATE OR REPLACE TRIGGER TRG_USER_INFO_BI:我创建一个触发器,名字叫TRG_USER_INFO_BIOR REPLACE是为了后面万一要修改触发器内容,可以直接替换掉旧的,不用先删除再新建。
  • BEFORE INSERT ON USER_INFO:这个是触发器触发的时机。意思是在每次向USER_INFO表插入数据之前。因为我要在插入前就把主键值准备
  • FOR EACH ROW:这个也很关键。表示每次插入一行数据,都会触发一次这个操作。而不是一次插入多行,只触发一次。
  • BEGIN ... END;:这里面就是触发器要干的活儿。
  • SELECT USER_INFO_* INTO :*_ID FROM DUAL;:这句是核心。USER_INFO_*就是获取USER_INFO_SEQ这个序列的下一个值。:*_ID代表的是即将插入的新行(:NEW)的USER_ID字段。FROM DUAL是Oracle里的一个虚拟表,通常用来执行一些不需要从实际表获取数据的查询,比如获取系统时间或者序列值。这句命令的含义就是把序列的下一个值塞给新行的USER_ID

搞定后的实用小技巧

这样一套搞下来,我的USER_INFO表就有了自增主键了。我往表里插入数据的时候,根本不用管USER_ID,它自己就给我填好了。

INSERT INTO USER_INFO (USER_NAME, EMAIL) VALUES ('张三', 'zhangsan@*');
INSERT INTO USER_INFO (USER_NAME, EMAIL) VALUES ('李四', 'lisi@*');

当我查询表的时候,就能看到USER_ID分别是1、2,完美。

这里面还有几个我当时也学到的小技巧,顺便分享出来。

  • NEXTVALCURRVAL的区别NEXTVAL是获取序列的下一个值,每次调用都会让序列前进一位。而CURRVAL是获取序列的当前值,前提是你必须先调用过一次NEXTVAL。也就是说,在一个会话里,NEXTVAL至少得先跑一次,你才能用CURRVAL。我一般是直接用NEXTVAL,因为是给新数据赋值,肯定需要新值。
  • 如果需要查看当前序列的下一个值:可以SELECT USER_INFO_* FROM DUAL;,但是要注意,这会消耗掉一个序列值!所以通常不建议没事儿就去查。
  • 如果需要重置序列:这个情况比较少,但万一测试环境需要,或者数据清理了想从头开始,那就得先DROP SEQUENCE USER_INFO_SEQ;,然后重新CREATE SEQUENCE。这个操作得小心,因为一旦删了,之前缓存或者用过的序列值就可能乱套,生产环境要慎重。

这套组合拳下来,Oracle的自增主键问题就算彻底解决了。虽然比别的数据库多走了两步路,但胜在灵活,而且搞懂了背后的逻辑,用起来也踏实多了。我把这个实践记录下来,希望也能帮到有同样困惑的朋友们。