LAST_INSERT_ID 是什么
MySQL 的 LAST_INSERT_ID() 返回当前连接最近一次插入所生成的自增主键。它是连接级的值,不随其它连接的变化而变;多行插入时返回第一行的值。PostgreSQL 没有这个函数,用 INSERT ... RETURNING 取回主键才是标准做法。
基本信息
| MySQL | LAST_INSERT_ID(),按连接隔离,不会读到别的事务的结果 |
|---|---|
| 多行插入 | 返回第一行生成的自增值,不是最后一个 |
| PostgreSQL | 用 INSERT ... RETURNING id 一步取回 |
| PG 序列取值 | currval(pg_get_serial_sequence('表','列')),需同会话先取过一次 |
| 禁止写法 | 不要用 SELECT MAX(id),并发下必然取错 |
| 连接池 | 取值必须与插入在同一条连接上完成 |
MySQL 取值
MySQL 取值
INSERT INTO orders (user_id, amount) VALUES (10, 99.00);
SELECT LAST_INSERT_ID(); -- 本连接本次插入生成的主键
INSERT INTO orders (user_id, amount)
VALUES (10, 1.00), (10, 2.00); -- 多行插入
SELECT LAST_INSERT_ID(); -- 返回第一行生成的那个值
-- 需要拿到全部主键时,逐行插入或用其它方式回查PostgreSQL 取值
PostgreSQL 取值
INSERT INTO orders (user_id, amount) VALUES (10, 99.00)
RETURNING id, created_at; -- 推荐:插入与取值在一条语句里完成
-- 需要知道序列名时的写法
SELECT currval(pg_get_serial_sequence('orders', 'id'));
-- currval 要求本会话已经取过该序列,否则直接报错取值方式对比
| 方式 | MySQL 8 | PostgreSQL |
|---|---|---|
| 插入即取回 | 没有 RETURNING,需要再查一次 | INSERT ... RETURNING 一步完成 |
| 取自增主键 | LAST_INSERT_ID() | RETURNING id 或 currval |
| 批量插入 | 返回首行生成的值 | RETURNING 逐行返回 |
| 并发安全 | 连接级取值,安全 | RETURNING 与 currval 安全 |
| 错误做法 | SELECT MAX(id) | SELECT MAX(id) |
典型使用场景
- 下单后立刻拿订单号写入明细表
- 批量导入后回填主表与从表的关联关系
- 写主表后把主键写进日志或消息,供下游消费
- 把自增主键作为幂等键回传给调用方
- 数据修复脚本插入补录记录并记录新主键
- 排查取值异常:确认插入与取值是否走了同一条连接
这个值是连接级的、与表无关:同一个连接里先插 A 表再插 B 表,返回的是最近一次针对自增列的插入值。连接池场景务必确认两步走的是同一条连接。
SELECT MAX(id) 在并发写入下几乎必然出错:读到的是别人插入的更大值,还会给主键查询增加额外扫描。自增主键必须用连接级函数或 RETURNING 取回。