当前位置:首页 > 问答 > 正文

数据库主键怎么自动增长,写SQL语句实现自增的那些事儿

在数据库里,给每一条新加入的数据一个独一无二的“身份证号”是非常重要的事情,这个“身份证号”就是我们常说的主键,手动去管理这个号码非常麻烦,容易出错,比如两个人同时操作,可能就会给两条数据分配同一个号码,这就乱套了,数据库提供了“自动增长”的功能,让数据库自己来操心这个号码的分配,我们只需要告诉它:“下一条数据来了,你给它个新号就行。”

不同的数据库,实现这个“自动增长”的方法不太一样,但核心思想是相通的,下面我们就来看看几种常见的数据库是怎么做的。

MySQL。 MySQL的做法非常直接了当,它使用一个叫 AUTO_INCREMENT 的关键字,你在创建表的时候,直接在想要自动增长的那个主键字段后面加上这个关键字就行了,我们要创建一个用户表,希望每个新用户都有一个唯一的ID,可以这样写SQL语句:

CREATE TABLE users (
    id INT NOT NULL AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    PRIMARY KEY (id)
);

(根据MySQL官方文档关于AUTO_INCREMENT的说明)这样建好表之后,当你往表里插入新用户数据时,就完全不用管id这个字段了,比如执行:INSERT INTO users (username, email) VALUES ('张三', 'zhangsan@example.com'); 数据库会自动把第一条数据的id设置成1,第二条是2,以此类推,非常简单省心。

接下来是SQL Server。 SQL Server的思路和MySQL类似,但它用的关键字是 IDENTITY,这个单词的意思就是“身份标识”,也很形象,它的写法上有一点细微差别,需要指定自动增长的“起始值”和“步长”,还拿创建用户表举例:

CREATE TABLE users (
    id INT IDENTITY(1,1) PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100)
);

(根据Microsoft SQL Server文档对IDENTITY属性的描述)这里的 IDENTITY(1,1) 意思是,从1开始,每次增加1,你也可以设置成 IDENTITY(100,5),那就是从100开始,每次增加5,插入数据的方法和MySQL一样,忽略id字段即可。

然后是PostgreSQL。 PostgreSQL采用了一种更接近标准SQL语法的做法,它使用了一种叫做“序列”的独立对象来管理这个自增的数字,虽然听起来复杂了一点,但PostgreSQL提供了一个快捷方式,让我们用起来和MySQL一样方便,它提供了两种数据类型:SERIALBIGSERIAL(一个用于普通整数,一个用于更大的整数),创建表的语句是这样的:

数据库主键怎么自动增长,写SQL语句实现自增的那些事儿

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100)
);

(根据PostgreSQL官方文档对SERIAL类型的解释)当你把字段的类型定义为 SERIAL 时,PostgreSQL会在后台自动为你创建一个专用的序列,并把这个序列和id字段关联起来,插入数据时,同样不需要指定id的值。

最后我们看看Oracle数据库。 Oracle的做法和PostgreSQL早期的思路很像,它也是明确地要求你先创建一个“序列”对象,然后在插入数据时,手动从这个序列中获取下一个值,这个过程分为两步:

第一步,创建序列:

CREATE SEQUENCE user_id_seq
  START WITH 1
  INCREMENT BY 1
  NOCACHE;

这条语句创建了一个名为user_id_seq的序列,从1开始,每次增加1。NOCACHE是为了保证号码的连续性,避免因为缓存丢失而出现跳号。

数据库主键怎么自动增长,写SQL语句实现自增的那些事儿

第二步,在插入数据时使用这个序列:

INSERT INTO users (id, username, email)
VALUES (user_id_seq.NEXTVAL, '李四', 'lisi@example.com');

(根据Oracle数据库关于序列的文档)这里的关键是 user_id_seq.NEXTVAL,它表示从user_id_seq这个序列中取出下一个值,作为本次插入的id,这种方式比前三种要稍微麻烦一点,需要显式地调用一下,但它非常灵活,你可以让多个表共用一个序列,或者在不同的地方更精细地控制这个值的获取。

总结一下这几种方法,可以发现一个有趣的现象:MySQL和SQL Server的方式是“声明式”的,你在建表时声明这个字段要自动增长,后面就不用管了,而Oracle是“命令式”的,需要你主动下达命令(NEXTVAL)去获取新值,PostgreSQL的SERIAL则是一种语法糖,背后是序列机制,但用起来像声明式,兼顾了方便和灵活。

除了知道怎么用,还有一些实际使用中会遇到的事情值得一说,自增主键的值一旦分配了,即使你后来把那条数据删掉了,这个号码也不会被回收再利用,这是为了避免出现混乱,想象一下,如果号码回收,可能会引起很多数据关联上的错误,在并发量特别高的场景下,如何高效地分配这些ID而不产生瓶颈,也是一个高级话题,有些大型系统会采用雪花算法之类的分布式ID生成方案来替代数据库的自增主键,但那已经是更复杂的故事了。

数据库的自增主键是一个基础且极其有用的功能,它把我们从一个繁琐易错的管理工作中解放出来,让我们能更专注于业务逻辑本身,虽然不同数据库的语法有差异,但只要我们理解了“自动分配唯一标识”这个核心概念,就能很快地上手使用。