LAST_INSERT_ID()是MySQL中唯一可靠获取刚插入自增ID的方式,它返回当前连接最近一次INSERT生成的第一个自增ID,不依赖表名、不受并发干扰,但必须在同一连接中紧接INSERT后调用。

MySQL用 LAST_INSERT_ID() 拿刚插入的自增ID
执行 INSERT 后立刻调用 LAST_INSERT_ID(),它返回当前会话最后一次 INSERT 生成的自增值,不依赖表名、不受其他会话干扰。注意它必须在同个数据库连接里紧接插入之后调用,中间不能穿插别的 INSERT(哪怕插的是另一张表)。
常见错误是把查询拆成两个独立请求发给连接池,比如先发 INSERT,再发 SELECT LAST_INSERT_ID()——这两个可能落到不同物理连接上,结果取到的是别人插入的 ID。
- 正确做法:在同一个
mysql_query()或execute()调用后,立刻用同一连接执行SELECT LAST_INSERT_ID() - 更稳妥的写法是合并为一条语句:
INSERT INTO users(name) VALUES('Alice'); SELECT LAST_INSERT_ID();(某些驱动支持多语句) - 如果用预处理语句(
PREPARE+EXECUTE),LAST_INSERT_ID()依然有效,但不能在PREPARE的 SQL 字符串里直接拼接它
PostgreSQL 必须用 RETURNING 子句
PostgreSQL 不提供类似 LAST_INSERT_ID() 的会话级函数,唯一可靠方式是在 INSERT 语句末尾加 RETURNING id(假设主键叫 id)。它会在插入成功后直接返回指定列的值,原子性强,且支持返回多列甚至表达式。
容易忽略的是:如果表用了序列(SERIAL)但主键不是靠 NEXTVAL() 自动填充(比如手动指定了 id 值),RETURNING id 返回的就是你写的那个值,不是新生成的——这点和 MySQL 的 LAST_INSERT_ID() 行为本质不同。
- 基本用法:
INSERT INTO users(name) VALUES('Bob') RETURNING id; - 想同时拿多个字段:
RETURNING id, created_at, token - 不能对已存在的行用
ON CONFLICT DO UPDATE后还指望RETURNING总返回新 ID;冲突时它返回的是更新后的行,ID 不变
SQL Server 的 SCOPE_IDENTITY() 是最安全的选择
SQL Server 有三个类似函数:@@IDENTITY、SCOPE_IDENTITY()、IDENT_CURRENT()。只有 SCOPE_IDENTITY() 能确保拿到当前作用域(当前批处理或存储过程)内本次 INSERT 产生的 ID。另外两个要么跨触发器污染,要么跨会话不安全。
典型陷阱是 ORM(如 Entity Framework)默认可能用 @@IDENTITY,一旦表上有触发器插入了另一张带自增列的表,就返回错 ID。手动写 SQL 时务必显式写 SELECT SCOPE_IDENTITY()。
- 必须和
INSERT在同一个批处理中,用分号或GO隔开就失效 - 不能在函数里调用(SQL Server 函数禁止副作用操作),只能在存储过程或应用层 SQL 中用
- 如果插入多行,
SCOPE_IDENTITY()只返回第一行生成的 ID(不是最大值)
ORM 框架里别硬写原生 SQL 来取 ID
主流 ORM(如 SQLAlchemy、MyBatis、Django ORM)都内置了主键回填机制,比如 SQLAlchemy 的 session.flush() 后模型实例的 id 字段自动赋值,MyBatis 的 useGeneratedKeys="true"。自己拼 SELECT LAST_INSERT_ID() 或 RETURNING 很容易破坏事务边界或连接复用逻辑。
尤其要注意 PostgreSQL + SQLAlchemy 的组合:如果没在 Table 定义里显式设 primary_key=True 和 server_default=func.nextval(...),即使写了 RETURNING,ORM 也可能忽略返回值。
- Django 中确保模型字段有
AutoField或BigAutoField,save()后直接读obj.id - MyBatis 的
<insert></insert>标签必须配useGeneratedKeys="true"且keyProperty指向对象属性名 - 不要在事务未提交前就调用
LAST_INSERT_ID()并缓存结果——万一事务回滚,这个 ID 就作废了,但数据库里可能已被跳过

















