← [ BACK_TO_NOTES ]

Mutation(状态变更操作)

Mutation 在应用开发中通常表示以改变 authoritative state 或触发业务副作用为目的的写操作/命令,与 Query/Read 相对;它不等同于某个 HTTP Method、数据库 UPDATE 或乐观更新。

#concept #growing #api

[!info] related notes

  • 所属 MOC:
  • 前置概念:
  • 并列概念:
  • 易混淆概念:
  • 关系笔记:

Mutation(状态变更操作)

一句话定义

在应用开发语境里,Mutation 通常不是中文日常语义里的“突然突变”,而是:

一个以改变系统状态或执行有业务副作用的命令为目的的操作。

中文理解成“状态变更操作”“写操作”“变更命令”通常比机械翻译成“突变”更自然。

最基本的对照是:

Query / Read
→ 读取、观察系统状态

Mutation / Write / Command
→ 改变系统状态或触发业务动作

为什么中文“突变”容易误导

英文 mutate 的基础语义就是 change / alter(改变、变更)。中文里“mutation”常因为生物学语境被翻成“突变”,容易让人产生“突然、剧烈变化”的联想,但软件工程里通常没有这个含义。

所以看到:

mutation
mutate state
useMutation
GraphQL Mutation

先翻译成:

变更
修改状态
写操作
状态变更操作

会更符合真实工程语义。

这个词在软件里还有另一种常见上下文

除了 API / Server State 的 Mutation,还经常看到:

mutate an object
mutate an array
state mutation

这里通常指直接改变一个已有对象当前保存的状态。

例如 JavaScript:

const items = [1, 2]
items.push(3)

push() 改变了原数组本身,因此可以说:

items was mutated

相比之下:

const nextItems = [...items, 3]

创建新数组而不改原数组,属于 immutable update 风格。

因此两个常见上下文可以这样区分:

Programming object mutation
→ 修改某个现有对象/数据结构的状态

API / Server-state Mutation
→ 发起一个以改变应用/服务器 authoritative state 为目的的操作

两者共同核心都是 change state,只是作用层级不同。

这也解释了 React 为什么常说“不要直接 mutate state”:那里讲的是对象/状态值的可变更新问题,不是 GraphQL/TanStack/Next.js 的网络 Mutation API。

最常见的 Mutation

CRUD 中:

Create → Mutation
Read   → Query
Update → Mutation
Delete → Mutation

但 Mutation 的范围比数据库 CRUD 更大。例如:

createGoal
updateProfile
cancelRun
sendEmail
logout
approvePayment
markNotificationRead
archiveTask
publishArticle
startWorkflow

这些操作不一定都直接执行 SQL INSERT / UPDATE / DELETE,但它们的业务意图都是“让系统从一个状态转移到另一个状态”或“要求系统执行一个有副作用的命令”。

Mutation 不等于数据库 UPDATE

错误理解:

Mutation
= SQL UPDATE

更准确:

Mutation
= application / API semantic write operation

例如:

sendEmail

可能没有更新业务数据库,但会产生外部副作用;

cancelRun

可能更新状态机、写事件、终止 Worker;

logout

可能撤销 Session 或 Token。

所以 Mutation 更接近 Command / Use Case,而不是某条具体数据库语句。

Mutation 不等于 POST

HTTP Method 和 Mutation 是两个不同维度。

常见情况:

POST   → 往往是 Mutation
PUT    → Mutation
PATCH  → Mutation
DELETE → Mutation
GET    → 按 HTTP 语义应当是安全读取,不应以修改资源为主要目的

但不能简单写成:

Mutation === POST

因为有些 POST 可能只是复杂查询入口,而 Mutation 的核心判断是业务语义是否以改变状态为目的。

Mutation 与副作用的关系

Mutation 通常意味着业务副作用,例如:

状态改变
消息发送
任务入队
缓存失效
外部支付调用
文件写入

但不要反过来把“任何实现副作用”都叫 Mutation。

例如一个 Query 可能顺便:

写 access log
增加 metrics counter
记录 trace

它的公开业务语义仍然是 Query,因为调用者并不是为了改变业务状态而发起它。

因此判断 Mutation 应看:

operation contract / business intent,而不是函数内部是否碰巧产生了任何副作用。

Query 与 Mutation 的关键区别

Query
→ 我想知道现在是什么

Mutation
→ 我想让系统发生什么

例如 MemoFlow:

listGoals()
→ Query

createGoal()
→ Mutation

completeTask()
→ Mutation

BodySense:

getAssessment()
→ Query

updateAssessment()
→ Mutation

cancelRun()
→ Mutation

这个视角和 Command/Query Separation 很接近:读取与改变状态的意图应该尽量清晰分开。

Mutation 不等于非幂等

另一个常见误区:

Mutation
= 每调用一次都会产生不同结果

不一定。

幂等性回答:

同一个操作重复执行多次,最终状态是否和执行一次相同?

Mutation 回答:

这个操作是否以改变状态为业务目的?

因此:

PUT resource/123
→ Mutation
→ 可以设计成幂等

DELETE resource/123
→ Mutation
→ 通常也可以是幂等语义

POST /payments
→ Mutation
→ 往往不是天然幂等,需要 idempotency key

所以:

Mutation / Query
≠
Idempotent / Non-idempotent

是两条不同轴。

Mutation 在不同技术里的同一语义

GraphQL

mutation CreateGoal {
  createGoal(...) { ... }
}

GraphQL 用 Mutation root type 显式表达写操作。详见 GraphQL Mutation 与错误语义。

TanStack Query

useMutation({
  mutationFn: createGoal,
})

这里 Mutation 表示客户端发起的 server-state 写操作,并管理 pending / success / error、optimistic update、rollback 与 cache reconciliation。详见 Mutation 完整生命周期。

Next.js Server Actions

"use server"
export async function createGoal(...) { ... }

Server Action 通常作为 React UI 内部的服务端 Mutation 入口。详见 Next.js Server Actions。

三个技术 API 完全不同,但共享一个核心语义:

intent = change server/application state

Mutation 与 Optimistic Update 不是一回事

Mutation 是:

真正要求服务器执行状态变更

Optimistic Update 是:

服务器尚未确认 Mutation 成功
→ UI 先预测成功结果
→ 成功后 reconcile
→ 失败则 rollback

所以:

Mutation
= business operation

Optimistic Update
= mutation UX / client projection strategy

一个 Mutation 完全可以不用乐观更新;一个乐观更新必须最终与真实 Mutation 结果收敛。

Mutation 后为什么常要处理缓存

一旦 authoritative state 改变:

Old Cache
≠
New Truth

因此完整链路通常是:

Mutation
→ authoritative state changes
→ invalidate / patch cached projection
→ refetch / revalidate / reconcile
→ UI converges

不同框架只是 API 不同:

TanStack Query
→ invalidateQueries / setQueryData

Apollo
→ normalized cache update / refetch

Next.js
→ updateTag / revalidateTag / revalidatePath

底层问题都是同一个:写操作之后,旧 projection 怎么重新和 truth 一致。

最短记忆

Mutation
不要死记成“突变”

更适合记成:
状态变更操作 / 写操作 / Command

Query
= 告诉我现在是什么

Mutation
= 让系统发生某种变化
创建于 2026/9/16 更新于 2026/9/16
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本