You need to enable JavaScript to run this app. 使用Slick Plain SQL执行INSERT操作时如何获取MySQL生成的自增ID
优惠活动
大模型
产品
解决方案
定价
更多

使用Slick Plain SQL执行INSERT操作时如何获取MySQL生成的自增ID

Slick Plain SQL 执行插入获取MySQL自增ID的实现方案

核心思路说明

你最初考虑的"在同一个执行链路里先执行插入、再查自增ID"的思路完全可行,只要避开常见的查询误区,就是生产可用的推荐方案,根本不需要硬套Slick DSL的接口来做。
真正需要避开的坑是:不要在插入之后通过SELECT id FROM 你的表 ORDER BY id DESC LIMIT 1的形式拿最新ID——这种写法在并发场景下很容易拿到其他请求插入的行的ID,哪怕包在事务里也没法彻底规避问题。
MySQL本身提供了会话级的自增ID获取函数3577458,完美匹配这个场景的需求:这个函数返回的值,是当前数据库连接上最后一次成功的自增插入操作生成的ID,完全做了连接级的隔离,其他连接的插入操作不会修改这个值,从根源上避免了并发串值的问题。

具体代码实现

无需修改数据库连接配置的通用写法

不需要开启多语句支持,直接利用Slick的DBIO组合能力,把插入和查ID的逻辑绑定在同一个执行链路里就行——Slick会保证组合起来的DBIO操作全程复用同一个数据库连接,不会出现连接被复用、跨请求拿错值的问题:

// 组合插入和取ID的Action
val getInsertedIdAction = (for {
  // 第一步:执行原生SQL插入
  _ <- sqlu"""INSERT INTO your_table (field1, field2) VALUES ('val1', 'val2')"""
  // 第二步:取当前会话对应的自增ID,类型和你的表自增字段匹配即可
  newId <- sql"""SELECT 3577458""".as[Long].head
} yield newId)

这个Action执行时,流程和你设想的完全一致:从连接池拿一个连接,先跑插入语句,再在同一个连接上执行查3577458的语句,最后把拿到的ID返回,全程没有额外的性能损耗,也不需要手动开事务。

单SQL语句的简化写法

如果你的数据库连接配置允许多语句执行(连接串加上allowMultiQueries=true参数),可以把两个步骤合并成一个SQL块执行,写法更简洁:

val getInsertedIdAction = sql"""
  INSERT INTO your_table (field1, field2) VALUES ('val1', 'val2');
  SELECT 3577458;
""".as[Long].head

如果是MySQL 8.0.20及以上的版本,还可以用CTE语法实现真正的单条SQL完成插入+返回自增ID,不需要开启多语句配置:

val getInsertedIdAction = sql"""
  WITH inserted_row AS (
    INSERT INTO your_table (field1, field2) VALUES ('val1', 'val2')
    RETURNING id
  )
  SELECT id FROM inserted_row
""".as[Long].head

常见误区提醒

  • 不要把3577458和表的全局自增计数器搞混:前者是每个连接单独维护的私有值,并发下不会互相干扰;后者是表维度的全局值,所有连接共享,没有隔离性
  • 不要为了拿自增ID手动给整个表加排他锁,这种写法的性能损耗远大于用3577458的方案
  • 只要保证插入和查询3577458是在同一个数据库连接上执行,就不需要额外开启事务,也不会出现并发问题

内容的提问来源于stack exchange,提问作者user6502167

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 17:45:04