不同数据库获取自增ID方式各异:MySQL用LAST_INSERT_ID()(同连接紧接调用)、PostgreSQL推荐RETURNING id(原子性好)、SQL Server用SCOPE_IDENTITY();避免SELECT MAX(id)并发风险;ORM中应配置useGeneratedKeys或自动赋值而非手拼SQL。

INSERT后立刻拿到自增ID,得看数据库类型
不同数据库返回自增主键的方式完全不同,不能写一套SQL通吃。MySQL、PostgreSQL、SQL Server各自有专属语法,混用会报错或返回NULL。
- MySQL用
LAST_INSERT_ID(),必须在同个连接里紧接INSERT之后调用 - PostgreSQL用
RETURNING id(推荐),或currval('table_id_seq')(需知道序列名) - SQL Server用
SCOPE_IDENTITY(),比@@IDENTITY更安全(避免触发器干扰)
MySQL:别用SELECT MAX(id),用LAST_INSERT_ID()
SELECT MAX(id) 看似简单,但在并发插入时极大概率拿错ID——别人刚插了一条,你查到的就是他的。而 LAST_INSERT_ID() 是连接级函数,只返回当前连接最近一次INSERT生成的ID,安全可靠。
INSERT INTO users (name, email) VALUES ('Alice', 'a@example.com');
SELECT LAST_INSERT_ID();
- 必须在同一个数据库连接中执行,跨连接无效
- 即使INSERT失败,
LAST_INSERT_ID()也不会变,不会误返回上一次成功的ID - 如果INSERT带多行(
VALUES (...), (...)),它只返回第一行生成的ID
PostgreSQL:优先用RETURNING,一行搞定
PostgreSQL的 RETURNING 是最干净的方案:INSERT和取ID合并为一条语句,原子性强,无需额外查询,也不依赖序列名。
INSERT INTO users (name, email) VALUES ('Bob', 'b@example.com') RETURNING id;
- 返回结果就是刚插入那行的
id值,可直接读取 - 支持返回多个字段,比如
RETURNING id, created_at - 如果表没显式定义序列(比如用
GENERATED ALWAYS AS IDENTITY),RETURNING依然有效,不用手动查序列名
ORM里怎么写?别手动拼SQL
用Django、SQLAlchemy、MyBatis这类ORM时,插入后取ID是内置行为,但默认可能不触发。关键不是“怎么写SQL”,而是“怎么配ORM让它自动返回”。
- Django的
model.save()后,model.id自动更新,前提是主键字段没设editable=False - SQLAlchemy用
session.flush()+obj.id,或直接session.add(obj); session.commit()后读obj.id - MyBatis的
<insert></insert>标签要加useGeneratedKeys="true"和keyProperty="id",否则id字段保持null
手写原生SQL再封装一层获取ID,往往绕过ORM优化,还容易漏掉事务绑定或连接复用问题——真正该花时间的是确认ORM配置是否生效,而不是反复调试SQL。


















