全书目录

第二十二篇:Prisma 完全指南 —— 数据翻译官事务所宇宙

第九章:事务 —— 公证打包办理窗口

1 分钟 323 字 第 408 / 962 个阅读单元

在软件城市里,有些手续不能办一半。

比如:

  • 创建订单后必须创建订单项
  • 发布文章后必须写审计日志
  • 扣库存和写支付流水必须要么都成功,要么都失败

这时候就要去事务所的公证打包窗口

transaction

#Prisma 里常见三类事务心智
#1. 依赖前一步结果的写入:用嵌套写入
ts
await prisma.user.create({
  data: {
    email: "team@city.dev",
    posts: {
      create: { title: "欢迎来到事务所" },
    },
  },
});

这类场景里,后面的记录依赖前面创建出的关系。

#2. 多个互相独立的写入:用 $transaction([])
ts
await prisma.$transaction([
  prisma.post.deleteMany({ where: { authorId: 7 } }),
  prisma.user.delete({ where: { id: 7 } }),
]);

心智是:

text
这些操作互相独立
但我要它们作为一个原子包一起提交
#3. 先查、再判断、再写:用交互式事务
ts
await prisma.$transaction(async (tx) => {
  const post = await tx.post.findUnique({
    where: { id: 1 },
    select: { published: true },
  });

  if (!post) {
    throw new Error("文章不存在");
  }

  if (post.published) {
    return;
  }

  await tx.post.update({
    where: { id: 1 },
    data: { published: true },
  });

  await tx.auditLog.create({
    data: {
      action: "PUBLISH_POST",
      entity: "Post",
      entityId: 1,
    },
  });
});
#一个特别容易踩坑的点

很多人会想:

ts
await prisma.$transaction(async (tx) => {
  await Promise.all([
    tx.user.update(...),
    tx.post.update(...),
  ]);
});

然后以为“这样就并行更快”。

但事务本质上要走同一连接,数据库连接同一时刻只能执行一个查询。
所以在事务里,Promise.all 不会把它变成你想象中的“真并行魔法”。