TT Lab
开始
学习 学习路径 课程

不可撤销的变更

获批的两笔订单不是任意两笔订单

在 TT Lab 中继续学习

一句话总结

变更审批不是“可以改多少条”的许可。它是关于改哪个客户的哪一行、从什么状态改到什么状态的约定。

为什么需要它

庆典运营方因为下雨,要求取消一部分小吃订单。早上查询了两笔待处理订单并获得批准。中午要执行时,发现其中一笔订单被其他负责人改了数量,同一个客户的新待处理订单也进来了。如果重新执行早上用的 WHERE 条件,就可能把批准时并不存在的订单也一起取消。SELECT 当时是对的这件事,和之后的 UPDATE 遵守了批准范围这件事,并不相同。

上一节课缩小了宽泛的请求,并准备了备份和中止标准。现在加入时间这个变量。人在阅读审批文档的时候,数据库一直在变化。如果从读取到应用期间锁住整张表,期间的其他业务就会停摆。所以要把批准时点的观测留成小而明确的数据,在执行时比较这份观测是否仍然有效。比较失败就停下来重新获得批准,不能悄悄地用当前值改写计划。

工作原理

本实验的批准对象是 id、revision、qty 三个值。客户标识 tenant 作为单独的参数传递。例如,批准的是 blue 客户的订单 1 在 revision=3、qty=7 时的状态,那么应用条件中要同时包含这些值和 pending 状态。只有 ID,就可能覆盖其他负责人改过的值;只有版本,就可能改到其他客户的行。这不是检查某一个值的装置,而是保存所批准的全部事实的契约。

승인 때: 고객 blue / 주문 1 / 버전 3 / 수량 7 / pending
적용 때: 고객 blue / 주문 1 / 버전 4 / 수량 7 / pending
판단: 수량이 같아도 버전이 바뀌었으므로 재확인

版本不是最后一个数字,而是用来区分变更历史的标记。数量可能从 7 变成 8 再变回 7。仅仅比较值,无法区分这种往返。本契约的前提是,所有正常的业务变更都会让 revision 增加。如果其他程序不遵守这条规则去修改表,保护范围就会不同,所以在生产环境中,还必须同时管理写入路径和权限。本实验中的一个令牌,并不能控制所有写入程序。

批准集合要做成按 ID 排序的副本。目的是不要因为以相反的顺序收到同样的两个对象,就把它看作不同的变更。反过来,同一个 ID 出现两次,会产生对同一行处理两次的歧义,所以予以拒绝。空列表也不会当作成功来处理。如果接受数量为 0 的执行,丢失了输入的 bug 就可能被记录成什么事也没发生就结束的正常作业。本课使用 1 到 16 个的小批次。

数字校验也不只是单纯的防御代码。在 Python 中,True 是 int 的子类型,所以宽松的检查可能让它像订单 ID 1 一样混进来。批准材料中的布尔值被当成编号,就是数据解释错误。要为 id、revision、qty 规定准确的整数范围,并拒绝 bool。为了让其他代码修改返回的计划时,原始输入不会一起改变,每个对象也要复制成新的 dict。

在现场相遇的样子

客户问得最多的,不是 SQL 语法,而是影响范围。要能说明:为什么只改这两笔订单、其他客户为什么不受影响、批准之后如果有变化,由谁来重新判断。因此,变更工具的输入必须与给负责人看过的计划相连。如果工程师读到的 CSV 和实际执行的清单不一致,即使有审批流程也不安全。

实际的 FDE 工作,与理解客户的问题、用数据和应用来解决、并对部署负责的工作相连。下面的 Palantir 公开招聘启事也要求与客户协作、以架构和数据为中心的实现。但这并不意味着该启事要求某种特定的 PostgreSQL 技巧或本示例的 schema。这里用一个小的虚构案例,练习这个角色所需要的变更范围说明和实现验证。不使用真实的客户数据或个人信息。

也要区分留下计划和获得权限。把 tenant 字符串传给函数,并不意味着调用者获得了变更该客户的权限。这个函数是在权限负责人调用的前提下,检查并发修改冲突。在生产 API 中,登录、客户范围权限、批准主体、审计留存策略都必须另行强制执行。不要把测试用的数据库账户当作真实服务生产账户的示例。

下一项检查要做什么

在接下来的测验中,要区分数量相同但 ID 不同、值相同但版本不同、重复 ID 和空的批准。在之后的综合实验中,会在两个真实的 PostgreSQL 连接之间,让通过 preview 观测到的计划变得过期,然后确认应用是否被拒绝。这是练习:不要悄悄地只把失败的对象换成新值,而是重新确认变更的前提。

参考:Palantir FDSE 招聘启事、PostgreSQL UPDATE。该启事于 2026-09-13 确认,并不意味着保证录用或考试出题范围。