以下是一个为期 10 周、每周末练习一个核心概念的实战任务清单。我们以 Python + FastAPI 为技术栈,从零开始构建一个“简易订单系统”,逐步把前面学到的理论点全部落地。
项目初始化(一次性准备,不占周末)
在第一个周末之前,先用最短时间搭好项目骨架:
1
2
3
4
|
mkdir order-system && cd order-system
python -m venv venv && source venv/bin/activate # Windows: venv\Scripts\activate
pip install fastapi uvicorn sqlalchemy pydantic pytest httpx
git init
|
创建文件 main.py,写一个最简 Hello World,验证可运行:
1
2
3
4
5
|
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello"}
|
运行 uvicorn main:app --reload,看到页面即表示就绪。之后每个周末都在这个项目上继续。
第 1 周:RESTful API 设计
目标
用 FastAPI 实现符合 REST 规范的订单 API,体会资源、HTTP 方法、状态码、路径参数的意义。
任务
- 设计
Order 资源模型(使用 Pydantic)。
- 实现以下端点,并严格遵守 REST 语义:
POST /orders — 创建订单(返回 201 Created)
GET /orders/{order_id} — 获取单个订单(200 / 404)
GET /orders — 获取订单列表(可加查询参数 ?status=paid)
DELETE /orders/{order_id} — 删除订单
- 暂时用内存列表存储订单,不涉及数据库。
所需 FastAPI 特性
APIRouter,路径参数/查询参数,Response(status_code=...),Pydantic 请求体与响应模型。
验收标准
能用 curl 或 httpie 完成 CRUD,并通过返回的 HTTP 状态码区分成功/失败。
第 2 周:依赖注入(DI)
目标
借助 FastAPI 的 Depends,将服务层从路由函数中解耦,并通过 DI 灵活切换实现。
任务
-
创建 IOrderRepository 接口(抽象基类),以及内存实现 InMemoryOrderRepository。
-
创建 OrderService 类,接收 IOrderRepository 作为构造参数。
-
使用 Depends 将 OrderService 注入到路由中:
1
2
3
4
5
6
7
8
9
|
def get_repo() -> IOrderRepository:
return InMemoryOrderRepository()
def get_service(repo: IOrderRepository = Depends(get_repo)) -> OrderService:
return OrderService(repo)
@router.post("/orders")
def create(order: OrderCreate, service: OrderService = Depends(get_service)):
...
|
-
额外准备一个 FakeOrderRepository(打印日志的实现),通过修改 get_repo 函数一行代码切换存储方式,体验“可插拔”。
验收标准
不修改路由函数,只改一个 Depends 工厂函数,就能让订单服务使用不同的存储实现。
第 3 周:单一职责原则(SRP) & 开闭原则(OCP)
目标
将接口层的验证、业务逻辑、数据访问彻底分离,使各模块职责单一;通过抽象扩展新功能而不改旧代码。
任务
- 拆分
OrderService:将输入验证逻辑迁移到独立的 OrderValidator 类中。
- 将
Order 生成逻辑与持久化逻辑分离。
- 引入“支付方式”概念,定义
PaymentMethod 抽象类,实现 CreditCardPayment 和 PayPalPayment。
- 在
CheckoutService 中依赖 PaymentMethod 接口(通过构造注入),增加新的支付方式时只需新增类,CheckoutService 代码不变。
验收标准
每个类的职责清晰可描述(一句话说明);新增 BitcoinPayment 时,只需要增加一个文件,原 CheckoutService 不需改动。
第 4 周:设计模式(工厂、策略、观察者)
目标
用组合代替条件分支,实现运行时动态切换算法,并用观察者实现支付成功的事件通知。
任务
- 策略模式:实现
DiscountStrategy 接口,提供 NoDiscount、BlackFridayDiscount、VIPDiscount。OrderPricingService 通过 DI 或 Setter 接收当前策略,计算最终价格。
- 工厂模式:创建
PaymentFactory,根据请求参数(如支付类型字符串)返回对应的 PaymentMethod 实例。工厂内部可使用简单判断或字典映射。
- 观察者模式:当支付成功后,
PaymentProcessor 调用已注册的 PaymentObserver 列表(如 StockObserver 扣库存、PointsObserver 赠积分)。观察者列表通过构造函数注入。
验收标准
能通过传入不同折扣策略获得不同价格;支付成功后控制台能看到各观察者触发信息;新增观察者只需添加一个类并注入即可。
第 5 周:单元测试与 TDD
目标
为业务逻辑编写测试,体验“先写测试、再写实现、最后重构”的 TDD 节奏。
任务
- 为
OrderValidator 编写单元测试(使用 pytest):
- 空金额订单应抛出异常
- 负数金额应抛出异常
- 有效订单通过验证
- TDD 实现一个新功能:结算时,若订单金额 < 0.01,不允许支付。先写失败的测试,再用最少代码通过,最后重构。
- 为
CheckoutService 写测试,用 unittest.mock 模拟 PaymentMethod 和 Repository,确保不连接真实支付和数据库。
- 使用
pytest 和 httpx 的 TestClient 对 FastAPI 端点进行集成测试,注入假存储。
验收标准
pytest 覆盖核心服务逻辑;所有测试秒级运行;能通过 pytest --cov 看到覆盖率报告。
第 6 周:重构
目标
在测试的保护下,识别代码坏味道并系统性地改善内部结构。
任务
- 检查现有代码,找出以下坏味道并修复:
- 长函数 → 提取函数(Extract Method)
- 参数列表过长 → 引入参数对象(如用
OrderPricingRequest 封装价格计算参数)
- 条件表达式过多 → 用多态替换条件(支付方式、折扣策略已经是多态,可验证)
- 重复代码 → 提取公共逻辑
- 重构过程中持续运行
pytest,确保测试始终绿灯。
- 使用
git 在重构前后分别打 tag(v0.1, v0.2),对比变化。
验收标准
重构前后功能完全不变,代码行数减少或结构更清晰,测试全部通过。
第 7 周:版本控制(Git)工作流
目标
模拟团队协作流程,掌握分支管理、Pull Request、提交规范。
任务
- 在 GitHub/GitLab 创建远程仓库,推送当前代码。
- 采用简化版 Git Flow:
- 从
main 创建 develop 分支。
- 每个新功能从
develop 拉 feature/xxx,开发后合并回 develop。
- 热修复从
main 拉 hotfix/xxx,修复后合并到 main 和 develop。
- 提交信息遵守规范:
feat: 添加订单备注字段, fix: 空金额验证未生效。
- 在
feature/logging 分支上添加一个日志功能,发起 Pull Request(自己 review 自己),利用 Diff 审查改动,然后合并。
- 使用
git rebase -i 整合历史(例如压缩多个微小提交)。
验收标准
仓库中有 main、develop 和至少两个已合并的功能分支;提交历史清晰可读;完成一次 PR 流程。
第 8 周:CI/CD
目标
为项目配置自动化构建、测试和代码检查流水线。
任务
- 使用 GitHub Actions(或 GitLab CI)编写 CI 配置文件(
.github/workflows/ci.yml):
- 触发条件:推送
main、develop 或任何 PR。
- 步骤:安装 Python,安装依赖,运行
pytest,运行 flake8 或 ruff 代码风格检查,运行 mypy 静态类型检查(可选)。
- 配置自动生成测试覆盖率报告,并上传到 Codecov。
- (可选)构建 Docker 镜像,推送到 Docker Hub。
- 提交代码,观察 GitHub Actions 自动运行并收到通过/失败反馈。
验收标准
当推送代码到 GitHub 时,自动运行测试和 lint,失败会收到通知。保证代码在合并前经过自动化验证。
第 9 周:领域驱动设计(DDD)基础
目标
用 DDD 术语重新组织订单领域,明确实体、值对象、聚合、仓储和领域服务。
任务
- 定义值对象:
Money(金额+币种,不可变)、Address(城市+街道,不可变)。
- 定义实体:
Order(有唯一 ID,生命周期状态可变,包含 Money 和 Address),OrderLine(订单行,属于订单聚合内部)。
- 明确聚合:
Order 为聚合根,外部只能通过 OrderRepository 访问订单,且不能直接修改内部行。
- 仓储接口:
IOrderRepository 定义 save(Order)、find_by_id(UUID) 等方法,返回领域模型而非数据库模型。
- 领域服务:
PricingService 封装价格计算逻辑(组合各种策略),属于无状态领域服务。
- 应用层通过 DI 获取仓储和领域服务,协调流程。
验收标准
领域模型与持久化模型分离;聚合根保证内部一致性(如添加订单行必须通过 Order.add_item,并校验金额);值对象不可变,使用 __eq__ 进行值比较。
第 10 周:数据库事务与隔离级别 + 架构模式
目标
为系统接入真实数据库,处理并发事务问题,并按整洁架构 / MVC 思想分层整理代码。
任务
- 用 SQLAlchemy 实现
SqlOrderRepository,通过 DI 替换内存仓储。
- 设置 SQLite(或 PostgreSQL)数据库,在 FastAPI 中使用
Database.dependency 管理会话。
- 实现“库存扣减”逻辑:
StockService.decrease 需要与订单创建在同一事务中(使用 @transact 或 with Session.begin())。
- 模拟并发下单:
- 编写一个并发测试,多线程同时抢购同一商品,验证不会超卖(可设置事务隔离级别
SERIALIZABLE 或用 SELECT ... FOR UPDATE 锁)。
- 测试不同隔离级别下的表现,记录差异。
- 最后重构项目目录为 Clean Architecture 风格(或 MVC):
1
2
3
4
5
|
app/
api/ # 路由、依赖
domain/ # 实体、值对象、仓储接口
application/ # 用例/应用服务
infrastructure/ # 数据库实现、外部服务
|
- 确认依赖方向:
api → application → domain ← infrastructure,infrastructure 实现 domain 接口,通过 DI 注入。
验收标准
并发测试中库存不会变成负数;换用不同隔离级别时可演示幻读或不可重复读现象(用日志/打印证明);最终项目结构分层清晰,内层不依赖外层。
总结表
| 周数 |
概念 |
核心实践 |
FastAPI/工具 |
| 1 |
RESTful API 设计 |
资源建模、HTTP 方法、状态码 |
FastAPI 路由、Pydantic |
| 2 |
依赖注入(DI) |
Depends、解耦路由与服务 |
FastAPI Depends |
| 3 |
SRP & OCP |
拆分验证器、支付方式接口扩展 |
抽象基类 |
| 4 |
工厂、策略、观察者 |
折扣策略、支付工厂、支付事件观察者 |
设计模式实现 |
| 5 |
单元测试 & TDD |
编写测试、mock、TDD 一个新功能 |
pytest、TestClient |
| 6 |
重构 |
提取函数、以多态替换条件、消除重复 |
git tag |
| 7 |
Git 工作流 |
分支模型、PR、rebase、提交规范 |
GitHub / GitLab |
| 8 |
CI/CD |
GitHub Actions 自动测试与 lint |
GitHub Actions |
| 9 |
DDD 基础 |
值对象、实体、聚合、仓储、领域服务 |
领域建模 |
| 10 |
事务/隔离级别 & 架构模式 |
并发扣库存、隔离级别验证、分层架构重构 |
SQLAlchemy、Clean Arch |
参考答案
完全理解!之前那个清单看起来有点抽象,现在我们直接用 Python/FastAPI 写出来,每个练习都附带一个“参考答案”,你可以边看边改、边跑边理解。下面是 10 周的周末练习计划,每周一个核心概念,包含目标、说明和可运行的代码骨架。
第 1 周:单一职责原则(SRP)
目标:把“创建依赖 + 业务逻辑 + 发通知”混在一起的大函数拆开。
练习:重构下面的 order_router,让它只负责接收请求和调用服务。
参考答案:拆成三个独立的类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
# main.py
from fastapi import FastAPI, Depends
app = FastAPI()
# ---------- 职责分离 ----------
class OrderValidator:
def validate(self, order: dict):
if order.get("total", 0) <= 0:
raise ValueError("金额必须大于0")
class OrderRepository:
def save(self, order: dict):
print(f"订单 {order['id']} 已保存到数据库")
class EmailSender:
def send(self, to: str, message: str):
print(f"邮件发送至 {to}: {message}")
# ---------- 服务层(只做调度) ----------
class OrderService:
def __init__(self, validator: OrderValidator,
repository: OrderRepository,
email_sender: EmailSender):
self.validator = validator
self.repository = repository
self.email_sender = email_sender
def process(self, order: dict):
self.validator.validate(order)
self.repository.save(order)
self.email_sender.send(order["email"], "订单已创建")
# ---------- DI 容器(手动模拟) ----------
def get_order_service():
return OrderService(OrderValidator(), OrderRepository(), EmailSender())
# ---------- 路由 ----------
@app.post("/orders")
def create_order(order: dict, service: OrderService = Depends(get_order_service)):
service.process(order)
return {"status": "ok"}
|
关键点:OrderService 不再自己 new 任何东西,每个类只做一件事。
第 2 周:开闭原则(OCP)
目标:增加一种支付方式时,不改动 Checkout 类。
练习:实现 PaymentMethod 接口,并通过 DI 注入到 Checkout。
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
from abc import ABC, abstractmethod
# ---------- 抽象接口 ----------
class PaymentMethod(ABC):
@abstractmethod
def pay(self, amount: float) -> str:
pass
# ---------- 具体实现 ----------
class CreditCard(PaymentMethod):
def pay(self, amount: float):
return f"信用卡支付 {amount} 元"
class PayPal(PaymentMethod):
def pay(self, amount: float):
return f"PayPal 支付 {amount} 元"
# ---------- 使用方(对修改关闭) ----------
class Checkout:
def __init__(self, payment: PaymentMethod):
self.payment = payment
def execute(self, amount: float):
return self.payment.pay(amount)
# FastAPI 示例:通过查询参数选择支付方式
from fastapi import FastAPI, Query, Depends
app = FastAPI()
def get_payment(method: str = Query("credit")):
if method == "credit":
return CreditCard()
elif method == "paypal":
return PayPal()
else:
raise ValueError("不支持的支付方式")
@app.get("/pay")
def pay(amount: float, checkout: Checkout = Depends(lambda: Checkout(get_payment()))):
# 实际项目中 Depends 里应根据请求参数构建 checkout
return {"result": checkout.execute(amount)}
|
当你想加比特币支付时:只需新增 BitcoinPayment 类,并在工厂里加一个分支,Checkout 一行不改。
第 3 周:依赖倒置原则(DIP) + 依赖注入
目标:高层模块 OrderService 只依赖抽象 Database 接口,不依赖具体的 MysqlDatabase。
练习:将数据库访问抽象为 Database 接口,并通过构造函数注入。
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
from abc import ABC, abstractmethod
# ---------- 抽象(高层模块依赖它) ----------
class Database(ABC):
@abstractmethod
def save(self, data: dict):
pass
# ---------- 具体实现(低层模块) ----------
class PostgresDatabase(Database):
def save(self, data: dict):
print(f"Postgres 保存: {data}")
class InMemoryDatabase(Database):
def __init__(self):
self.storage = []
def save(self, data: dict):
self.storage.append(data)
print("内存保存")
# ---------- 业务逻辑 ----------
class UserService:
def __init__(self, db: Database):
self.db = db
def create_user(self, name: str):
self.db.save({"name": name})
# FastAPI 使用依赖注入选择实现
from fastapi import FastAPI, Depends
app = FastAPI()
# 切换数据库只需改这里
def get_database() -> Database:
return InMemoryDatabase() # 或 PostgresDatabase()
@app.post("/users")
def create_user(name: str, service: UserService = Depends(lambda: UserService(get_database()))):
service.create_user(name)
return {"user": name}
|
关键点:依赖方向反转了——UserService 不 import 具体数据库。
第 4 周:工厂模式
目标:将对象的复杂创建逻辑从业务代码里移走。
练习:创建支付方式的工厂,支持从配置文件读取类型。
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 支付工厂
class PaymentFactory:
@staticmethod
def create(payment_type: str) -> PaymentMethod:
if payment_type == "credit":
return CreditCard()
elif payment_type == "paypal":
return PayPal()
else:
raise ValueError(f"未知支付方式: {payment_type}")
# 在 FastAPI 中使用
def get_payment_from_factory(method: str = "credit"):
return PaymentFactory.create(method)
# 路由不变,工厂负责创建
|
如果引入新支付方式,只需修改工厂(或将其升级为注册表模式,完全符合 OCP)。
第 5 周:策略模式
目标:动态切换折扣算法,比如“无折扣”、“黑五大促”。
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
from abc import ABC, abstractmethod
# ---------- 策略接口 ----------
class DiscountStrategy(ABC):
@abstractmethod
def apply(self, price: float) -> float:
pass
class NoDiscount(DiscountStrategy):
def apply(self, price):
return price
class BlackFridayDiscount(DiscountStrategy):
def apply(self, price):
return price * 0.5
# ---------- 上下文 ----------
class PriceCalculator:
def __init__(self, strategy: DiscountStrategy):
self.strategy = strategy
def calculate(self, price: float):
return self.strategy.apply(price)
# FastAPI 依赖注入 + 工厂
from fastapi import FastAPI, Query
app = FastAPI()
def get_discount_strategy(campaign: str = Query("none")):
if campaign == "blackfriday":
return BlackFridayDiscount()
return NoDiscount()
@app.get("/price")
def get_price(original: float, calculator: PriceCalculator = Depends(
lambda campaign=Query("none"): PriceCalculator(get_discount_strategy(campaign))
)):
# 实际中需要配合 Depends 传参,这里为了简洁直接 Lambda
return {"final_price": calculator.calculate(original)}
|
真正运行时需要改造 Depends,但策略模式的核心结构就是这样。
第 6 周:观察者模式
目标:订单支付成功后,通知库存、积分、物流系统。
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
from typing import List
# ---------- 观察者接口 ----------
class OrderObserver:
def on_payment_success(self, order_id: str, amount: float):
pass
class InventoryObserver(OrderObserver):
def on_payment_success(self, order_id, amount):
print(f"[库存] 扣减库存,订单 {order_id}")
class PointsObserver(OrderObserver):
def on_payment_success(self, order_id, amount):
print(f"[积分] 增加积分,订单 {order_id}")
# ---------- 被观察者 ----------
class PaymentProcessor:
def __init__(self, observers: List[OrderObserver] = None):
self.observers = observers or []
def add_observer(self, observer: OrderObserver):
self.observers.append(observer)
def pay(self, order_id: str, amount: float):
print(f"支付成功,订单 {order_id}")
for obs in self.observers:
obs.on_payment_success(order_id, amount)
# FastAPI 组装
from fastapi import FastAPI, Depends
app = FastAPI()
def get_payment_processor():
processor = PaymentProcessor()
processor.add_observer(InventoryObserver())
processor.add_observer(PointsObserver())
return processor
@app.post("/pay/{order_id}")
def pay(order_id: str, amount: float,
processor: PaymentProcessor = Depends(get_payment_processor)):
processor.pay(order_id, amount)
return {"status": "paid"}
|
新增观察者只需加一个类,并在组装函数里添加,不影响 PaymentProcessor。
第 7 周:TDD 与单元测试
目标:为折扣计算写测试,体验“先写测试,再写代码”。
参考答案:使用 pytest。
1
2
3
4
5
6
7
8
9
10
11
|
# test_price_calculator.py
import pytest
from main import PriceCalculator, NoDiscount, BlackFridayDiscount
def test_no_discount():
calc = PriceCalculator(NoDiscount())
assert calc.calculate(100) == 100
def test_black_friday():
calc = PriceCalculator(BlackFridayDiscount())
assert calc.calculate(100) == 50
|
运行:pytest test_price_calculator.py。
TDD 流程:
- 先写上面的测试(此时可能对应的类还没写,测试失败)
- 再创建
NoDiscount 和 BlackFridayDiscount 使测试通过
- 重构代码,保持测试绿色
第 8 周:DDD 基础 – 实体与值对象
目标:用实体(具有唯一标识)和值对象(不可变)建模订单。
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
from dataclasses import dataclass
from uuid import uuid4
# ---------- 值对象(不可变) ----------
@dataclass(frozen=True)
class Address:
street: str
city: str
@dataclass(frozen=True)
class Money:
amount: float
currency: str = "CNY"
# ---------- 实体(有 ID,可变) ----------
class Order:
def __init__(self, customer_name: str, address: Address):
self.id = str(uuid4())
self.customer_name = customer_name
self.shipping_address = address
self.items = []
self.status = "NEW"
def add_item(self, product: str, price: Money):
self.items.append({"product": product, "price": price})
def total(self) -> Money:
total_amount = sum(item["price"].amount for item in self.items)
return Money(total_amount)
# ---------- 仓储接口(领域层定义) ----------
class OrderRepository(ABC):
@abstractmethod
def save(self, order: Order):
pass
# ---------- 基础设施实现 ----------
class InMemoryOrderRepository(OrderRepository):
def __init__(self):
self._store = {}
def save(self, order: Order):
self._store[order.id] = order
|
FastAPI 里可以通过 DI 注入 OrderRepository,完成聚合的持久化。
第 9 周:RESTful API 设计
目标:设计一组符合 REST 规范的订单 API。
参考答案:完整的 CRUD。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
app = FastAPI()
# ---------- 模型 ----------
class OrderCreate(BaseModel):
customer_name: str
amount: float
# ---------- 模拟数据库 ----------
orders_db = {}
# ---------- 路由 ----------
@app.post("/orders", status_code=201)
def create_order(order: OrderCreate):
order_id = str(uuid4())
orders_db[order_id] = order.dict()
return {"id": order_id, **orders_db[order_id]}
@app.get("/orders/{order_id}")
def get_order(order_id: str):
if order_id not in orders_db:
raise HTTPException(status_code=404, detail="未找到")
return orders_db[order_id]
@app.put("/orders/{order_id}")
def update_order(order_id: str, order: OrderCreate):
if order_id not in orders_db:
raise HTTPException(status_code=404, detail="未找到")
orders_db[order_id] = order.dict()
return {"id": order_id, **orders_db[order_id]}
@app.delete("/orders/{order_id}", status_code=204)
def delete_order(order_id: str):
if order_id in orders_db:
del orders_db[order_id]
return
|
使用合适的 HTTP 方法、状态码、名词资源。
第 10 周:数据库事务与隔离级别
目标:模拟转账操作,使用事务保证数据一致性。
参考答案:使用 sqlite3 和 FastAPI 的路由。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import sqlite3
from fastapi import FastAPI, HTTPException
app = FastAPI()
def get_connection():
conn = sqlite3.connect("bank.db")
conn.execute("PRAGMA journal_mode=WAL")
return conn
@app.post("/transfer")
def transfer(from_acc: str, to_acc: str, amount: float):
conn = get_connection()
try:
conn.execute("BEGIN")
# 检查余额
cur = conn.execute("SELECT balance FROM accounts WHERE name=?", (from_acc,))
row = cur.fetchone()
if not row or row[0] < amount:
raise ValueError("余额不足")
# 扣减
conn.execute("UPDATE accounts SET balance = balance - ? WHERE name=?", (amount, from_acc))
# 增加
conn.execute("UPDATE accounts SET balance = balance + ? WHERE name=?", (amount, to_acc))
conn.commit()
return {"status": "success"}
except Exception as e:
conn.rollback()
raise HTTPException(status_code=400, detail=str(e))
finally:
conn.close()
|
测试隔离级别:可以开启两个终端,用 sqlite3 命令行并发操作,观察 repeatable read 行为。