数据库服务开发:分层、Session 与事务回滚|课后复习
今天学会了什么
能解释 with 如何进入、退出并传播异常,验证成功、业务失败和提交失败后的资源清理;能在真实 MySQL 验证整笔订单回滚。
在图上找出订单头、全部明细与库存共用的提交点,再沿异常路径指出哪些变化必须一起撤销。
今天讲了什么(对照复习)
下面逐项对应课堂正文。先盖住右边那一栏,凭记忆回答;卡住了再翻回左边同名的小节。光说得出名字不算会,还要能讲清它会做什么、什么时候会失效。
| 课堂对应章节 | 必须能解释的机制与边界 |
|---|---|
| 四层职责和依赖方向;从文件错误迁移到数据库业务错误 | Model 管对象规则,Service 管用例和跨对象规则,持久化层管理读写,CLI/后续 Router 适配输入输出。数据库阶段沿用 CommerceError 下的 ResourceNotFound 等实际异常;旧文件 StorageCorruptedError 不替代数据库业务错误。 |
| SQLAlchemy:先认识表映射与连接工厂 | ORM 映射表与对象,不自动决定事务。Engine 可共享连接池,sessionmaker 是工厂,Session 是一次工作状态;Mapped/mapped_column 描述映射,不等于运行时业务校验。 |
| 先演示一个坏结果;事务是什么;原子下单只有一个提交点;autocommit 的陷阱 | 相关写入放进一个事务,全部成功才 commit,否则 rollback。循环逐项提交会留下半张订单;不能仅凭代码没写 commit 就忽略驱动和数据库的自动提交模式。 |
| Session 是什么;flush、commit、rollback | Session 取连接、追踪变更、发 SQL,结束后关闭并归还资源。flush 发出待写 SQL但未最终提交;commit 会先 flush 再提交;失败后 rollback 恢复事务边界,不能继续使用失败状态的 Session。 |
| Service 与 Unit of Work:一次用例一次事务 | UoW 汇合一次用例的数据访问与事务;Protocol 声明需要的方法,省略号不代表已实现。with 调用 enter/exit,具体实现负责未提交回滚和 close。查询订单关联明细时,joinedload 与 unique 分别处理关联读取和重复行。 |
| 用失败注入证明 rollback;rollback 通过要看到什么 | 第二条明细失败时,用独立查询比较前后:新订单头与明细不存在,两件商品库存均回到操作前。捕获异常或打印失败不证明回滚;稳定业务错误与数据库故障需区分。 |
| 先建立同步数据库服务,再讨论异步 | 今天直接用 Python/CLI 调用同步 Service,每个用例独立 Session。Fake 可验证规则,不证明 InnoDB 锁与约束;真实数据库集成另记,HTTP 翻译在下次课接入。 |
出了问题:怎么发现、怎么修、怎么验证
只在你自己那份课程副本或专用实验数据上复验,把改之前和改之后的真实结果都留下来。
| 风险/现象 | 提前预防 | 怎样发现 | 怎样处理 | 怎样复验 |
|---|---|---|---|---|
| 循环提交留下半张订单 | Service 统一事务,全部完成才提交 | 第二项失败后查询订单头、明细及两项库存 | 移除数据访问内部提交,统一 UoW | 全部前后事实符合回滚要求 |
| 全局 Session 或失败后不清理 | 每用例创建会话,退出必清理 | 观察异常后的下一次请求及连接占用 | rollback 后关闭;工厂共享、实例独立 | 失败后新用例正常,资源及时归还 |
| flush 被当成持久提交 | 标清 flush 与 commit 位置 | flush 后注入异常,再用新会话查询 | 保持单一最终提交点 | 未提交变化撤销,成功事务可查 |
| 业务异常名混用或连接故障冒充不存在 | 对照当前异常类型与职责 | 分别触发未知订单与连接不可用 | 上层按业务类型处理,保留底层诊断 | 两种错误可区分,错误细节不泄密 |
| Fake 通过冒充真实回滚 | 结果注明替身或真实库 | 核对连接环境和操作前后 SQL 结果 | 在课程 MySQL 重新执行失败注入 | 真实结果单独留证,未跑则待验证 |
本日新增 Python 知识怎样进入商城
enter/exit、异常传播、try/finally、contextmanager 单次 yield、closing;复用 Session/UoW/flush/commit/rollback。它们共同支持“整笔订单失败回滚与连接释放”。我应能打开 session_scope.py 指出每个机制的位置,并重跑 正常 commit→close;业务失败 rollback→close;提交失败仍关闭;真实第二项失败后核对三类表和库存。
| 风险 | 提前预防 | 怎样发现 | 怎样处理 | 怎样复验 |
|---|---|---|---|---|
| 异常被上下文压住 | 退出返回 False/None,捕获后重新抛出 | 失败实验却走到成功提示 | 恢复异常传播 | 调用者收到错误且 close 已发生 |
| 提交或业务失败资源未释放 | close 放 finally,事务策略统一 | 替身事件缺 close,实库连接未归还 | 修复退出边界,不在循环提交 | 正常/业务失败/提交失败分别回归 |
闭卷自测
先自己答一遍,再去运行或翻回课堂核对;不确定的地方标出来,别用 AI 的答案顶掉你自己的第一次判断。
-
说出一次创建订单各层负责什么;为什么 Router 或 CLI 不应自己提交数据库事务?
-
Engine、sessionmaker、Session 能否全部全局共享?flush 与 commit 有什么差别?
-
Protocol 的方法写了省略号是否可以执行业务?with 如何触发 UoW 的进入与退出?
-
第二个商品失败后,列出必须核对的订单、明细和库存事实。异常被捕获为什么不够?
-
Fake 测试、真实 MySQL 事务测试各能证明什么?如何避免把连接失败返回成资源不存在?
-
exit 返回 True 会怎样影响业务异常?生成器上下文管理器为何只 yield 一次?commit 失败时怎样验证 rollback 与 close?
再看一眼真实业务
有赞公开说明能确认订单与库存的业务关联;它没有证明后台是否使用单库事务。用自己的两明细失败记录解释课程实现怎样保护这个关联。
今天留下什么,下节课怎么接着用
同时保留本人 session_scope.py 及成功、业务失败、提交失败的生命周期记录,后续 API 继续使用同一资源边界。
保留数据库版 Service、UoW/Session 生命周期图、正常提交与第二项失败回滚证据,以及真实库/替身分栏结果。W02-D03 复用这些服务接 HTTP,不在路由里重写规则。
隔离级别、真实连接竞争和死锁在 W03-D01 深化;今天不以串行成功证明并发正确。
补充交接:D03 直接复用数据库服务,通过 HTTP 接入并补异步多源查询。本人 commerce_ops 每天增量合并,不用后一天骨架覆盖前一天实现。