首页 / Prisma ORM 入门教程 / 更新与删除:update、upsert 与原子操作

Prisma ORM 入门教程

更新与删除:update、upsert 与原子操作

本教程共 54 篇 · 第 20 篇 · 更新于 2026-08-11 · 约 4 分钟阅读

updateupdateManyupsert原子操作delete级联删除软删除CRUD

本节目标:掌握单条与批量的更新删除、幂等的 upsert、数值原子操作,并理解级联删除的陷阱。

改和删比查更需谨慎。这一章把更新、删除、幂等三件事讲全:单条与批量怎么改、怎么删,upsert 怎么做到「有就更新、没有就建」,以及级联删除有哪些坑。

更新单条:update

const user = await prisma.user.update({
  where: { id: 1 },
  data: { name: "新名字" },
});

where 必须唯一字段,data 里只写要改的字段,其余原样保留。记录不存在抛 P2025。update 也能带关系字段做嵌套更新,比如顺带改用户的资料表,这个能力在第 24 章展开。

批量更新:updateMany

const result = await prisma.post.updateMany({
  where: { published: false },
  data: { published: true },
});
// { count: 19 }

where 可以随意过滤,返回的是受影响条数 { count },不是记录本身。想拿回更新后的记录列表,用 updateManyAndReturn(PostgreSQL、CockroachDB、SQLite 支持):

const users = await prisma.user.updateManyAndReturn({
  where: { role: "USER" },
  data: { isActive: true },
});

upsert:更新或创建,一步到位

const user = await prisma.user.upsert({
  where: { email: "viola@prisma.io" },
  update: { name: "Viola" },
  create: { email: "viola@prisma.io", name: "Viola" },
});

先按唯一字段找,找到走 update,找不到走 create。两次执行结果一致,天然幂等,适合初始化数据、每日签到、统计计数这类逻辑。update 传空对象即可模拟 findOrCreate——「有就不动,没有就建」。

数值原子操作

计数加一、减库存这类场景,不能先读后写。两个请求同时读到 5,各自加一写回,结果变成 6 而不是 7。要用原子操作符,让数据库在内部完成计算:

await prisma.post.update({
  where: { id: 1 },
  data: {
    views: { increment: 1 },
    likes: { increment: 1 },
  },
});

四个操作符:increment、decrement、multiply、divide。点赞数、库存、余额这些高频变动的数字都该这么改,并发请求不会互相覆盖。

删除:delete / deleteMany

// 删单条,where 必须唯一字段
await prisma.post.delete({ where: { id: 1 } });

// 按条件批量删,返回 { count }
const result = await prisma.session.deleteMany({
  where: { expiresAt: { lt: new Date() } },
});

// 清空整表,慎用
await prisma.user.deleteMany({});

delete 返回被删记录,deleteMany 返回 { count }。deleteMany({}) 删光所有行,调试环境常用。删除前记得校验归属:where 里带上 userId 之类的归属字段,防止越权删除别人的数据。

级联陷阱

必填关系下,删除带子记录的用户会失败,报错大意是「这个操作会违反 PostToUser 的必填关系」。三种解法:

  1. 把关系改成可选(Post.author 加 ?),配合引用操作 onDelete: SetNull
  2. 先删子记录再删父记录,两条命令包在 $transaction 里,全部成功才提交
  3. 在 Schema 里声明 onDelete: Cascade,让数据库自动级联删除
Note

级联删除是 Schema 层面的配置,不是查询参数。引用操作的默认值(必填关系 Restrict、可选关系 SetNull)在第 14 章讲过,此处不再重复。

测试环境清空数据同理:按依赖顺序 deleteMany 子表再删父表,用 $transaction 包住保证原子。生产环境千万别这么干,用迁移和受控脚本。

硬删还是软删

硬删除直接删行,释放存储,但不可恢复。软删除给记录加 deletedAt 字段,删除只是更新标记:

// 软删除 = 更新标记
await prisma.user.update({
  where: { id: 1 },
  data: { deletedAt: new Date() },
});

两者取舍:

维度硬删除软删除
存储立即释放持续占用
恢复不可恢复置空 deletedAt 即可
查询不用管每处都要过滤 deletedAt: null

软删可恢复、可审计,适合用户和业务数据;代价是每处查询都要记得带 deletedAt: null 过滤。这个过滤条件可以用客户端扩展(Client Extensions)统一注入,第 36 章细讲。硬删适合会话、日志这类过期即弃的数据。

参考来源

  • Prisma 官方文档:CRUD(Update / Delete)
  • Mapagam:Working with Update Operations / Working with Delete Operations
  • Generalist Programmer:Prisma ORM Tutorial(Update / Delete Operations)