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

使用Prisma $transaction时触发Maximum call stack size exceeded错误

问题:Prisma事务中触发“Maximum call stack size exceeded”错误

原本使用JavaScript+Prisma操作PostgreSQL时,无事务的公司及关联起重机更新功能正常。引入Prisma $transaction 保证原子性后,执行时卡顿约1分钟,随后抛出“Maximum call stack size exceeded”错误,且数据库几乎为空,不存在大量更新操作。使用Prisma版本为9.8.1,相关代码如下:

const updateCompany = async (req, res, next) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return next(
      new HttpError('Invalid inputs passed, please check your data.', 422),
    );
  }

  const companyId = req.params.id;
  const { name } = req.body;

  try {
    const company = await companyRepo.getCompanyById(companyId);

    if (!company) {
      return next(new HttpError('Company not found.', 404));
    }

    // Update company name
    company.name = name;    
    delete company.updatedAt;

    // Start the transaction
    const result = await prisma.$transaction(async (tx) => {
      const updatedCompany = await companyRepo.updateCompanyById(
        companyId,
        company,
        tx,
      );

      const companyWithSitesAndCranes =
        await companyRepo.getCompanyWithSitesAndCranesById(companyId, tx);

      // update each crane we got from the company
      const sites = companyWithSitesAndCranes.sites;
      for (const site of sites) {
        for (const crane of site.cranes) {
          await craneRepo.updateCraneById(crane.id, {
            identityName: `${updatedCompany.name}-${site.name}-${crane.name}`,
            tx,
          });
        }
      }

      return updatedCompany;
    });

    // // without transaction
    // const updatedCompany = await companyRepo.updateCompanyById(
    //   companyId,
    //   company,
    // );

    // const companyWithSitesAndCranes =
    //   await companyRepo.getCompanyWithSitesAndCranesById(companyId);

    // // update each crane we got from the company
    // const sites = companyWithSitesAndCranes.sites;
    // for (const site of sites) {
    //   for (const crane of site.cranes) {
    //     await craneRepo.updateCraneById(crane.id, {
    //       identityName: `${updatedCompany.name}-${site.name}-${crane.name}`,
    //     });
    //   }
    // }

    return res.status(200).json(result);
    // return res.status(200).json(updatedCompany);
  } catch (err) {
    const error = new HttpError(
      err.message || 'Updating company failed.',
      err.code || 500,
    );
    next(error);
  }
};

const getCompanyWithSitesAndCranesById = (id, prismaClient = prisma) => {
  return prismaClient.company.findUnique({
    where: {
      id: id,
    },
    include: {
      sites: {
        include: {
          cranes: true,
        },
      },
    },
  });
};

const updateCompanyById = (id, company, prismaClient = prisma) =>
  prismaClient.company.update({ where: { id: id }, data: company });

const updateCraneById = (id, crane, prismaClient = prisma) => prismaClient.crane.update({ where: { id: id }, data: crane });

此前搜索得知该错误多与递归相关,但代码中无递归逻辑,求问题原因及解决方法。


解决方案

错误原因

核心问题是调用craneRepo.updateCraneById时参数传递错误:你把事务客户端tx作为更新数据对象的属性传入,而非作为第三个独立参数传递。

updateCraneById的定义明确接收三个参数:id、更新数据crane、可选的Prisma客户端prismaClient。但你在事务中的调用把tx放到了更新数据对象里,当Prisma处理data参数时,会递归遍历对象的所有属性来生成SQL语句,而tx内部包含大量循环引用的属性(比如与主Prisma客户端的关联、内部状态),导致递归遍历无限循环,最终触发栈溢出。

修复步骤

将tx作为第三个独立参数传递给craneRepo.updateCraneById,修改事务中的循环代码:

// 事务内的循环部分修改为:
const sites = companyWithSitesAndCranes.sites;
for (const site of sites) {
  for (const crane of site.cranes) {
    await craneRepo.updateCraneById(
      crane.id,
      { identityName: `${updatedCompany.name}-${site.name}-${crane.name}` },
      tx // 正确:作为第三个参数传递事务客户端
    );
  }
}

额外优化(可选)

如果起重机数量较多,可使用Promise.all批量执行更新,提升事务内的执行效率:

const updatePromises = [];
for (const site of sites) {
  for (const crane of site.cranes) {
    updatePromises.push(
      craneRepo.updateCraneById(
        crane.id,
        { identityName: `${updatedCompany.name}-${site.name}-${crane.name}` },
        tx
      )
    );
  }
}
await Promise.all(updatePromises);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 18:37:48