在软件城市里,有些手续不能办一半。
比如:
- 创建订单后必须创建订单项
- 发布文章后必须写审计日志
- 扣库存和写支付流水必须要么都成功,要么都失败
这时候就要去事务所的公证打包窗口:
transaction
#Prisma 里常见三类事务心智
#1. 依赖前一步结果的写入:用嵌套写入
await prisma.user.create({
data: {
email: "team@city.dev",
posts: {
create: { title: "欢迎来到事务所" },
},
},
});这类场景里,后面的记录依赖前面创建出的关系。
#2. 多个互相独立的写入:用 $transaction([])
await prisma.$transaction([
prisma.post.deleteMany({ where: { authorId: 7 } }),
prisma.user.delete({ where: { id: 7 } }),
]);心智是:
这些操作互相独立
但我要它们作为一个原子包一起提交#3. 先查、再判断、再写:用交互式事务
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,
},
});
});#一个特别容易踩坑的点
很多人会想:
await prisma.$transaction(async (tx) => {
await Promise.all([
tx.user.update(...),
tx.post.update(...),
]);
});然后以为“这样就并行更快”。
但事务本质上要走同一连接,数据库连接同一时刻只能执行一个查询。
所以在事务里,Promise.all 不会把它变成你想象中的“真并行魔法”。