2026-05-21 学习记录 —— SQLAlchemy、SQLModel、CQRS 骨架搭建
2026-05-21 学习记录 🎯
SQLAlchemy Core 硬啃官方文档、SQLModel 增删改查一对多多对多全过了一遍、CQRS 极简电商订单系统骨架搭建、分布式 ID 雪花算法、以及 FastAPI 作者原来是搞音乐的。
—— 塑梦
SQLAlchemy Core(官方文档硬啃)
第一遍完全看不懂,硬着头皮啃完发现其实就是用 Python 对象描述数据库:
- MetaData:装表的箱子
- Table:数据库表在 Python 里的替身
- Column:列
- ORM 模型(
class User(Base))底层自动生成这些东西
Core vs ORM:
| Core | ORM |
|---|---|
| SQL 表达式语言 | 操作 Python 对象 |
engine.connect() 直接说话 |
Session 雇秘书帮你管对象 |
engine.begin() 自动事务 |
|
engine.connect() 需手动 commit |
第一次看官方文档看不懂太™正常了。
SQLModel 深入学习
基础 CRUD
table=True= 数据库表,不写 = 纯 Pydantic 校验壳Field()把数据库参数和 Pydantic 校验全揉在一起autoincrementSQLModel 不认识,得塞进sa_column_kwargs或直接删掉——整数主键默认自增
一对多
ForeignKey写在多方,Relationship两边都要写back_populates的值是对方类里那个属性的名字,两边必须对得上- 核心作用:双向绑定——
article.author = user后user.articles自动出现此文章。不写的话各管各的
多对多
- 需要第三张中间表,用
link_model指定 - 两个外键组成联合主键天然防重复
- 但如果中间表要加数量字段,联合主键就不适用了——因为同一个商品不能在同一个订单里出现多次
逻辑外键
- 企业开发规范里禁用数据库物理外键
- ORM 层面仍然可以定义
Relationship,通过foreign_keys参数告诉 ORM 用哪列做关联 - JOIN 查询照样用,数据完整性靠应用代码
多数据库
- 不同表指定不同
metadata,分别create_all到不同数据库 - 代价是跨库不能 JOIN,需应用层手动多次查询拼接
Pyright 报错踩坑
Decimal在where()里比较报类型错误——Pyright 类型推断跟不上 SQLAlchemy 的动态特性,代码能跑scalars()是session.exec()之后的结果对象的方法,不是select()的方法——这个是真写错了
CQRS 练习:极简电商订单系统
架构
1 | |
亮点
- EventBus +
@BaseEvent.register装饰器注册投影,声明式且优雅 - command / event / projection / query 四层分离,符合 CQRS 标准姿势
Order.add_item()返回Self支持链式调用- Session 上下文管理器统一使用
踩坑
- 循环导入:
model.py顶部导入handler+handler.py顶部导入model→ Python 加载死锁。解决:把 import 移到方法内部(惰性导入) ClassVar用错:ClassVar[int]告诉 SQLModel”这不是数据库列”,外键建不出来Order(id=order_id):这是新建对象不是查数据库→session.get(Order, order_id)- 投影算术 bug:
_remove_item里total_price = get_total_price(order_id) + item.price写成了加号(感谢虚幻捉虫) - DDD 实体方法 vs Python 导入限制:从 DDD 角度看实体有自己的行为完全正确,但 Python 的导入机制不支持双向导入,需要惰性导入来绕开
分布式系统知识
- 自增主键问题:分布式下有尾部热点——所有插入往 B+ 树最后一页挤
- UUID 问题:非单调递增引起 B+ 树页分裂和重排,占 128bit
- 雪花算法:最常用分布式 ID 方案,支持最多 1024 台机器,每秒百万级 ID
- 时钟回拨问题:NTP 可缓解
- 生产环境数据库别用 Docker:有状态,扩缩容需复杂同步,资源隔离不如虚拟机
- 事件风暴:UX/UI → 指令 → 实体 → 规则 → 事件,从事件倒推建模
其他
- Diagrams:Python 代码画云架构图,自带 AWS/GCP/Azure 官方图标,比 Mermaid 更适合 PPT 汇报
- FastAPI 作者 Sebastián Ramírez:一个人写了 FastAPI + Typer + SQLModel,还深度参与了 Pydantic V2 的 Rust 核心——他原来是搞音乐的,这跨界离谱程度 🫠
sqlite:///:memory::连接不会被 SQLAlchemy 自动关闭(StaticPool),数据在整个程序运行期间都在- LeetCode 探险模式数据结构与算法:草率刷完(最后几道难的直接 CV 🤪)
评论