功能说明
该示例展示乐观并发的标准写法:读取记录并记下版本,修改后写回时把版本作为条件,只有存储中的版本仍等于读到的版本才允许写入。写入影响零行即表示期间他人改过,函数不据此抛错,而是返回带当前值的结果,交由调用方重读后重试或呈现冲突。
关键代码
存储接口把“保存并比对版本”抽成返回布尔的操作,真实实现可对应 SQL 的 UPDATE … WHERE id = ? AND version = ? 并按影响行数判断。更新总是把版本加一,保证每次成功写入都推进版本。冲突分支重新加载最新记录放入结果,避免调用方再次往返;记录消失是另一类错误,单独抛出。返回类型用可辨识联合区分成功与冲突。
使用注意
调用方在冲突后必须重读并重新施加变更,绝不能拿旧值盲重试,否则会覆盖他人改动或反复冲突。版本应使用整数并严格自增,避免用时间戳,因为同刻度内的两次写入可能无法区分。乐观锁适合读多写少;写密集场景下频繁冲突的重试会放大负载,此时悲观锁或串行化隔离可能更合适。
代码示例
export interface Record { id: string; value: string; version: number; }
export type UpdateResult = { ok: true; record: Record } | { ok: false; conflict: true; current: Record };
export async function updateWithVersion(
store: { load(id: string): Promise<Record | undefined>; save(record: Record, expectedVersion: number): Promise<boolean> },
id: string,
mutate: (value: string) => string,
): Promise<UpdateResult> {
const current = await store.load(id);
if (!current) throw new Error('record not found: ' + id);
const next: Record = { id, value: mutate(current.value), version: current.version + 1 };
const saved = await store.save(next, current.version);
if (!saved) {
const fresh = await store.load(id);
if (!fresh) throw new Error('record vanished during update: ' + id);
return { ok: false, conflict: true, current: fresh };
}
return { ok: true, record: next };
}