深入 Hibernate 01:同一数据库行对应几个 Java 对象
实验材料状态:下文保留先前 PostgreSQL 16.15 的原始记录。当前检出版本在专用 PostgreSQL 16.15 上复跑 00–03,6 项测试通过;新运行的报告在 examples/hibernate-lab/evidence/00-03/20261003T030855Z-pg16-cumulative/。主仓另保留 2026-10-02 的 PostgreSQL 17.6 原始运行;2026-10-03 同步后在 PostgreSQL 17.6 复跑 00–12,50 项通过,见 examples/hibernate-lab/evidence/00-12/20261003-pg17-synced-local/。两种环境的运行分别留证。 一行不是一个全局 Java 对象 订单服务按数据库主键查询 PurchaseOrder 两次,两次返回值是否满足 ==?只有在说明查询发生在哪个持久化上下文、上下文是否被清空之后,这个问题才有答案。同一张订单在不同请求中也可能同时以两个 Java 对象表示,不能据此推断数据库有两行,或从 Java 引用相同推断另一个事务的可见...
深入 Hibernate 00:从对象操作到数据库结果,证据链怎样建立
实验材料状态:下文保留先前 PostgreSQL 16.15 的原始记录。当前检出版本在专用 PostgreSQL 16.15 上复跑 00–03,6 项测试通过;新运行的报告在 examples/hibernate-lab/evidence/00-03/20261003T030855Z-pg16-cumulative/。2026-10-02 的 PostgreSQL 17.6 基线位于 examples/hibernate-lab/evidence/local-baseline/20261002-pg17/;同步后复跑 00–12,50 项通过,见 examples/hibernate-lab/evidence/00-12/20261003-pg17-synced-local/。系列主模块最终累计 136 项通过,见 examples/hibernate-lab/evidence/cumulative/20261003-pg17-final/。各环境与各轮运行分别留证。 问题是哪个观察者看到了订单 创建订单的代码执行到 persist(order),此时订单对象可能已经有 ...
系统设计 E05:从票务架构到可执行状态机
高层设计写着“座位最多卖一次”,类图里有 Seat、Order、Payment,并不能证明代码守住了这个约束。真正需要落地的是谁拥有状态、哪条操作能改变它、检查与更新是否处在同一原子边界,以及失败后返回什么可执行结果。 本篇把系列票务场景缩小为单座位占用与支付确认,使用 Python 标准库和实际 SQLite 数据库验证状态机。没有真实支付渠道,没有分布式锁,也不把这个小程序称为完整票务系统。目的是把架构层的数据保证变成模块契约与数据库操作,避免为名词各建一个类后仍然允许非法状态跳转。 对象边界由不变量决定 同一座位至多被一个有效持有人占用,已售座位不能因旧占座或迟到回调重新转给别人;同一支付 ID 重复通知不重复记录,同 ID 换持有人要拒绝。这里的“支付确认”是本地假支付事件,若不能完成销售,返回 refund_required 表示需要外部补偿,不表示已经退款。 状态只有 FREE、HELD、SOLD。占座从 FREE 进入 HELD,或在 HELD 到期后由新持有人重新占用;付款只能在当前 HELD 尚未到期、持有人匹配时进入 SOLD。SOLD 在本实验没有反向边,...
系统设计 E04:流式模型网关的取消与用量边界
流式接口发出第一段内容之后,失败重试就不再只是重新请求一次。用户可能已经看到半句,模型端可能已经产生全部用量,网关却只记录了几个片段。取消、计费与重试必须共享同一个请求状态,而不能由三个互不相干的中间件分别处理。 本篇设计多租户 LLM 服务网关,范围包含流式转发、有限并发、准入配额、显式取消和用量核对;排除真实模型推理、供应商账单、工具调用与训练。实验启动真实回环 HTTP 服务和客户端,但“模型”仅按序生成数字片段,每段不等于真实 tokenizer 的 token,结果不能用来估算任何模型价格或 GPU 吞吐。 把首段、完成和取消分别建模 业务不变量是一个请求不能同时占用多个有效执行槽,取消后其本地执行应释放资源,已发送部分输出的请求不能被透明重试成另一段独立回答。目标拟定为准入后首 token p99 两秒以内、显式取消在一秒内停止本地任务;完整回答延迟取决于输出长度,不能拿首 token 指标代替。 接口候选为 POST /generations,携带租户身份、请求 ID、输入与最大输出预算,返回流;POST /generations/{id}/c...
系统设计 E03:指标日志平台的基数与保留代价
指标平台常在查询量还不大时就被标签组合拖垮。一个请求计数器加上 user_id,不是多存一个字符串,而是可能把六十条时间序列变成六万条。保留期和降采样又会改变哪些历史问题还能回答,平台设计不能只报“每天写入多少 GB”。 本篇限定为内部服务指标与结构化日志,支持服务健康查询、地域汇总和单请求排查。排除完整 APM、全文搜索产品复刻与真实用户数据。写入确认只承诺进入约定持久层,查询需返回数据时间范围及缺失信息;已过期原始数据不得用降采样结果冒充原始精度。 先固定查询集,再选数据布局 三类查询决定三条访问路径:查询某服务最近一分钟最大延迟,需要细粒度窗口值;查询各地域总请求量,需要按有限标签聚合;查询 request_id 的错误日志,需要可定位明细。把三类数据都放同一套标签系统,会让单请求排查所需高基数标识污染常驻指标。 指标模型为 metric_name, labels, timestamp, value,标签集合标识一条序列;日志模型为 timestamp, service, level, request_id, body。写接口 POST /metrics/batch、PO...
系统设计 E02:事件归因的去重迟到与修正
同一笔转化被上报两次,是重复事件问题;点击在转化之后才到达,是迟到数据问题;转化原先归给广告甲、补齐数据后改归广告乙,是归因修正问题。把三者都交给“消息去重”处理,会让统计稳定地算错。 本篇只使用合成曝光、点击与转化,构建一个固定窗口的最后点击归因模型。没有真实广告用户数据,没有接入投放平台,也不计算应付账款。教学不变量是同一转化 ID 只进入一次业务总额、修正保持该笔总额守恒、窗口外点击不得获得归因。归因报表与资金账务的边界必须在模型之前确定。 事件时间、到达时间与业务时间不能混用 事件采用 event_id, kind, user_key, campaign_id, event_time, ingest_time;转化另带 conversion_id, amount_minor, currency。金额使用最小货币单位整数,本例 500 表示五百单位的教学金额,不暗示任何真实币种。身份关联键采用合成 u1,不讨论跨设备身份识别;若身份关联不可靠,归因本身应允许未知结果。 接入接口 POST /events 返回“已接受并持久保存”,不承诺归因结果立即最终化。查询 GET /...
系统设计 E01:协同编辑的收敛删除与光标
两个人离线在同一个字符前输入,重新联网后看到相同文本,只能证明副本收敛;它不能证明插入位置符合各自意图,也不能证明光标不会跳到另一段。多人编辑需要分别设计文本合并、删除语义与交互定位。 本篇讨论小型纯文本协同编辑,支持离线插入、删除和再次同步;不实现富文本、表格公式、权限撤销后的离线内容回收或生产级编辑器。关键不变量是同一有效操作集合产生相同可见文本、重复操作不重复插字、已删除字符不会因迟到插入消息复活。体验目标另外定义:本地键入立即回显,在线操作传播拟定 p99 小于 300 ms,离线恢复后明确显示同步状态。 从位置冲突理解 OT 与 CRDT 假设文档是 AB,两名作者都以整数偏移 1 插入 X、Y。一端先 X 后 Y,另一端先 Y 后 X,如果直接执行相同偏移,结果可能为 AYXB 与 AXYB。冲突不在网络丢消息,而在操作引用的“位置 1”依赖各端当时的文档版本。 操作转换 OT 可以根据已经应用的并发操作转换位置;常见集中式安排由服务器确定顺序,客户端对尚未确认的本地操作执行相应转换。正确性依赖转换函数、上下文和协议,不是简单把远端位置加一。CRDT 则把合并所需身...
系统设计 35:三场限时设计与约束改变复盘
短链、派单和票务都可以从单库开始,但十倍流量触发的修改不同。短链需要处理热读与撤销确认,派单需要拆开空间候选与司机归属,票务需要同时核算提交预算和外部扣款协议。复盘应留下旧方案在哪条约束下失效,以及新方案付出的代价。 这三场练习由 AI 执行者各在一个真实持续至少四十五分钟的窗口内完成。记录包含阶段稿、运行源码、正反例输出和约束注入时刻,原稿没有事后替换成最终答案。它们证明书面设计与代码核对过程;真人口述、实际支付渠道和生产吞吐尚未运行。 短链:热读不能绕开撤销 初始范围是创建、重定向、过期与撤销。创建响应丢失后,同一业务幂等键重试应返回同一个 code;同键换 target 要拒绝。撤销确认后开始的新读取不能再返回目标,已经在途的响应和复制出去的 URL 不在此保证内。 基准读取 2000 request/s、创建 20 request/s。按每条元数据 400 B、三十天保留、三份副本,正文为 20×86400×400×30×3=62.208 GB,索引和备份另算。读 p99 100 ms、创建 p99 300 ms 是教学目标,实验没有证明这些性能。 初稿采用单个 SQL...
系统设计 34:内容平台跨模块保证的四条路径
发布按钮返回成功、时间线出现一张卡片、搜索可以找到正文、好友收到通知,是四个不同的确认。把上传、时间线、搜索、消息和通知组合到同一张图上,并不会使这些确认自动同步。本篇用四条跨模块路径检查它们在哪里可以延迟,在哪里必须拒绝继续。 教学平台支持图片与短文本发布、关注时间线、公开内容搜索、私信和站内通知。排除广告竞价、推荐模型训练、视频转码和真实外部推送。核心不变量是未提交的上传不可见、已确认删除的内容不通过新读取泄露、客户端重连不会重复展示同一消息。搜索和通知允许延迟,但延迟不能变成权限旁路。 为每种状态确定权威来源 元数据采用 posts(id, owner, object_key, state, version, visibility),状态依次为 UPLOADING、LIVE、DELETED。对象上传与数据库无法仅凭两次成功响应成为原子事务,因此只有对象校验完成、元数据进入 LIVE 后才允许读者看到。未引用对象由扫描任务延迟回收,回收前检查上传会话和引用,避免删除仍在提交的对象。 发布接口 POST /posts 携带创建幂等键;上传会话另有 POST /uploads ...
系统设计 33:回填期间更新怎样安全迁移
迁移失败不一定发生在切流那一秒。旧库的一条 v1 记录被回填器读走,业务紧接着写入 v2,新库也已接收 v2;几秒后回填器把 v1 覆盖回去。两边都有记录、总行数相同、服务没有报错,用户却看到了旧值。 本篇把分享元数据从旧表迁到增加访问权限字段的新表。讨论在线回填、兼容读取与可回退范围,排除真实跨数据库复制的实现。本次本机实验使用 SQLite 3.51.3 执行版本条件 UPSERT;跨库原子性、CDC 完整性和线上性能不在实验结论内。 先确定迁移后必须相同的东西 业务不变量是同一分享的较旧版本不能覆盖较新版本,撤销墓碑不能被回填复活;同一个创建幂等键仍指向同一分享。迁移成功不是两个库行数接近,而是指定切换位点之前的业务状态可解释一致。读取目标拟定为 p99 200 ms、写入 p99 300 ms、回填每天不超过原存储可用 IO 的二成,这些是计划预算,不是本实验测出的能力。 旧模型为 shares(id, target, version, deleted),新模型增加 owner_id, visibility, schema_version。更新接口 PATCH /sha...












