You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prisma如何可靠返回最后插入行?使用MySQL存储过程能否实现相同效果?

方案1:修改存储过程直接返回插入ID(最优解)

你可以直接调整现有EM_ADDMSG存储过程的逻辑,在插入操作完成后直接返回生成的自增ID,无需依赖会话变量或额外跟踪表:

-- 存储过程末尾添加如下逻辑
SELECT 2932661 AS new_id;

调用存储过程时直接使用$queryRaw获取返回结果即可:

const result = await prisma.$queryRaw`call EM_ADDMSG(${myVar1}, ${myVar2}, ${myVar3}, NULL, NULL, NULL, ${myVar4})`;
const newId = result[0][0].new_id;

该方案完全规避了跨请求变量污染的问题,性能损耗最小,也不会产生死锁。

方案2:将会话变量查询和存储过程调用放入同一事务(无需改存储过程)

之前会话变量返回重复ID的核心原因是Prisma连接池复用了同一个数据库会话,不同请求的存储过程调用覆盖了@id的值。你可以将call存储过程和查@id两个操作放入同一个Prisma事务中,事务会独占一个数据库连接,全程不会被其他请求复用,天然避免变量污染:

const newId = await prisma.$transaction(async (tx) => {
  await tx.$executeRaw`call EM_ADDMSG(${myVar1}, ${myVar2}, ${myVar3}, NULL, NULL, NULL, ${myVar4}, @id)`;
  const idRes = await tx.$queryRaw`SELECT @id AS new_id`;
  return idRes[0].new_id;
});

注意这里要用Prisma的参数化模板字符串语法,不要手动拼接SQL字符串,避免SQL注入风险。

方案3:优化现有跟踪表方案解决死锁

如果你必须保留现有的跟踪表逻辑,可以做两处优化解决死锁问题:

  • 给跟踪表用于筛选的唯一标识符字段添加唯一索引,避免delete操作时全表扫表产生的表级锁,大幅降低死锁概率
  • 给事务增加重试逻辑,捕获1213死锁错误后自动重试,最多重试2-3次即可覆盖绝大多数死锁场景:
async function runWithRetry(operation, maxRetries = 3) {
  let retryCount = 0;
  while (retryCount < maxRetries) {
    try {
      return await operation();
    } catch (err) {
      if (err.code === '1213' && retryCount < maxRetries - 1) {
        retryCount++;
        await new Promise(resolve => setTimeout(resolve, 50 * retryCount));
        continue;
      }
      throw err;
    }
  }
}

// 调用示例
const newId = await runWithRetry(() => {
  return prisma.$transaction([
    // 存储过程调用、跟踪表操作逻辑
  ]);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 21:15:04