第一幕:那些年,我们一起手动执行的 SQL
本地开发改了 Model然后把改表的 SQL 语句保存到一个 txt 或者 sql 文件里。上线的时候战战兢兢地连上生产数据库复制、粘贴、回车一气呵成。运气好一切顺利运气不好一个语法错误或者字段冲突整个上线流程就卡住了甚至更糟——服务直接崩了。这感觉像什么就像你开着一辆没有后视镜的跑车在高速上狂飙爽是爽但翻车也就是一瞬间的事儿。手动管理数据库变更就是咱们技术债里最危险的一笔。你可能会问“那用 Alembic 这种迁移工具不也是执行 SQL 吗有啥区别”问得好区别就在于它把变更版本化、自动化、可追溯、可回滚了。它就像是给你的数据库操作装上了“行车记录仪“和“倒车影像“让你每一步都心里有底。⚙️ 第二幕Alembic 到底是个啥三分钟搞懂核心三件套别被那些术语吓到Alembic 其实特简单。你可以把它想象成一个专业的数据库版本控制工具就像我们用 Git 管理代码一样。它有三个核心玩意儿咱们必须得认识一下-迁移脚本 (Migration Script)这就是那个记录了你这次要对数据库“做什么”的 Python 文件。里面主要是两个函数 upgrade() 是往前走加字段、建表 downgrade() 是往后退删字段、删表。-版本表 (alembic_version)Alembic 会在你的数据库里悄悄建一张表里面就一个字段记录着当前数据库结构对应的是哪个版本的迁移脚本。每次执行成功它就更新一下版本号。-配置文件 (alembic.ini env.py)alembic.ini 是全局配置主要告诉 Alembic 你的数据库地址在哪。env.py 是核心逻辑所在怎么连数据库、怎么生成脚本全在这儿定义。是不是以为这样就完了不对于咱们 FastAPI 玩家来说真正的挑战才刚刚开始因为我们用的是异步 第三幕FastAPI 异步环境下三步搞定 Alembic 配置好消息是Alembic 官方早就为我们这些异步党准备了专属模板再也不用像以前那样手写一大坨 env.py 配置了。你只需要用下面这个命令初始化alembic init -t async alembic这个 -t async 参数会直接给你生成一套适配 AsyncSQLAlchemy 的 env.py 和脚本模板省去了大量繁琐的手动改造工作。但别高兴得太早生成完不是就万事大吉了下面这三步“填空题”要是没做好照样翻车。第 1 步告诉 Alembic 你的 Model 长啥样打开生成的 alembic/env.py 找到 target_metadata None 这一行。它默认是空的Alembic 根本不知道你项目的表结构在哪儿。你得把它改成from your_app.models import Base # 改成你实际项目的导入路径 target_metadata Base.metadata第 2 步导入所有 Model 类紧接着上面那步还有一个巨坑。你必须在 env.py 里把所有的 Model 文件都导入一遍哪怕只是一个 import 不用它的任何东西也行。因为 Python 不导入那个模块 SQLAlchemy 的 Base.metadata 就不知道那个表存在我自己就吃过这个亏加了个新 Model跑 autogenerate 死活不生成建表语句排查半天发现是忘了在 env.py 里加一行 from your_app import new_model 。所以养成习惯在 env.py 最上面来一句 from your_app.models import * 一劳永逸。实测 * 有时会导致识别不到子模块安全的建议还是将所有自定义模型明确引入这里保留 * 是想提醒诸位全部引入全部引入全部引入第 3 步配置数据库连接串异步模板会从 alembic.ini 里的 sqlalchemy.url 读取连接信息。但你很可能在项目里用 Pydantic Settings 管理配置。所以更推荐的做法是在 env.py 里动态从你的配置对象读取 URL而不是写死在 .ini 文件里。这样切换开发/测试/生产环境才方便。做法很简单在 run_migrations_online 函数里找到读取配置的地方改成from your_app.config import settings # 在 run_migrations_online 函数里 config_section config.get_section(config.config_ini_section, {}) # 直接覆盖掉从 .ini 读来的 url config_section[sqlalchemy.url] settings.DATABASE_URL connectable async_engine_from_config( config_section, prefixsqlalchemy., poolclasspool.NullPool, )搞定这三步你的 Alembic 异步环境才算真正配置好了。是不是比想象中简单 第四幕标准工作流 生产级零停机的骚操作配好环境咱们的日常操作流就顺滑无比了1️⃣ 改完 Model 代码。2️⃣ 运行 alembic revision --autogenerate -m add_user_bio_field 。3️⃣停下来打开生成的迁移脚本瞪大眼睛仔细检查Alembic 自动生成的东西有时候会缺心眼比如它可能会把改字段名识别成先删后建这要是在生产环境跑了数据就没了4️⃣ 确认无误运行 alembic upgrade head 。接下来重点来了咱们聊聊千万级大表零停机部署的注意事项。如果你直接在几千万数据的表上通过 Alembic 加一个带默认值的字段数据库可能会锁住导致你的线上服务几分钟甚至几十分钟不可用。这绝对是一场灾难。根据以往的经验调整成这样的策略会更稳-向后兼容原则永远只做“加法”不做或少做“减法”。新加的字段必须允许为空 nullableTrue 并且不要设置默认值。设置默认值会导致数据库立刻去改写所有现有行这是锁表的元凶。-分步执行加字段分三步走。第一步执行迁移只加字段nullable。第二步部署新代码代码层面处理新字段为空的逻辑。第三步再写个后台脚本或者另一次迁移慢慢把所有旧数据的该字段填上值最后再考虑改成非空。这个工具的选择好比选螺丝刀不是最贵的就好而是用对了方法才顺手。Alembic 给你提供了螺丝刀但怎么拧螺丝不把板子拧裂还得靠经验和技巧。 写在最后好了关于 FastAPI Alembic 的这一套组合拳从入门到能抗生产差不多就是这些了。技术这条路从来没有什么银弹都是在解决一个又一个具体问题的过程中慢慢变得游刃有余的。希望我分享的这些踩坑经历能让你在面对数据库变更时少一丝慌张多一份从容。最后啰嗦一句不管用什么工具上线前多检查一遍迁移脚本这个习惯能救你无数次。嘿我是你的老朋友一名程序媛。这篇文章里聊的 -t async 用法和零停机策略都是我亲自趟过的坑总结出来的。如果你觉得有点用别藏着点个「赞」加「关注」分享给身边还在手动执行 SQL 的难兄难弟们吧。也欢迎留言区跟我聊聊你都在数据库迁移上栽过哪些跟头咱们下次见