数据库迁移与版本升级:别让升级变成事故

升级出问题,九成是没有备份、或者跳过了迁移检查。这两件事做到,剩下都是可恢复的小问题。

学完能做到 能安全地把一个私有化实例从旧版本升到新版本,出问题能回滚。

开始之前

  • 有服务器 SSH 权限
  • 知道数据库连接方式
  • 有停机窗口(建议安排在非生产时段)

操作步骤

第一步永远是备份,不是升级

备份两样:数据库(mysqldump 全量)和代码目录(tar 打包)。数据库备份要验证能恢复 —— 只看文件大小不算验证。备份文件建议下载一份到本地,避免服务器本身出问题。

看清有哪些待执行的迁移

cd backend && alembic current 看当前版本,alembic history 看历史链,alembic heads 看是否有多个 head(多个 head 说明迁移链分叉了,必须先合并再升级)。

先看迁移脚本再执行

不要直接 upgrade head。打开 alembic/versions/ 下待执行的文件看 op. 语句:有没有 drop_column、有没有大表加索引、有没有 NOT NULL 无默认值的列。有后两类要评估锁表时间和数据填充方案。

先升级数据库,再换代码

顺序很重要:新代码可能依赖新列,但旧代码不依赖。所以先用旧代码执行迁移(新列对旧代码无影响),再替换代码重启。反过来做会出现「新代码找不到列」的窗口期报错。

升级后跑三项冒烟

① 登录能进;② 一个核心列表能加载(订单列表);③ 一次写操作成功(新建一张订单或提交一次报工)。三项都过再开放给用户,不要一升级就喊大家用。

失败了怎么回滚

代码回滚:解包备份的 tar 覆盖目录,重启。数据库回滚:alembic downgrade -1(只适用于本版本迁移写了 downgrade 的情况);没写 downgrade 或数据已被改写,就只能从备份恢复。所以备份是唯一可靠的后悔药。

代码示例

bash完整升级流程(照着执行)
set -e
APP=/www/wwwroot/lightmes
TS=$(date +%Y%m%d-%H%M%S)

# 1) 备份代码
cd $APP
tar czf /root/backup-code-$TS.tar.gz backend/app backend/alembic frontend-admin-pro/src

# 2) 备份数据库(密码从 .env 取,避免明文出现在命令历史)
PW=$(grep '^DB_URL' backend/.env | sed -E 's#.*://[^:]+:([^@]+)@.*#\1#')
mysqldump -h127.0.0.1 -ulightmes -p"$PW" --single-transaction --routines lightmes \
  | gzip > /root/backup-db-$TS.sql.gz
ls -lh /root/backup-db-$TS.sql.gz

# 3) 检查待执行迁移
cd $APP/backend
./venv/bin/alembic current
./venv/bin/alembic heads

# 4) 执行迁移(旧代码状态下)
./venv/bin/alembic upgrade head

# 5) 替换代码(按你们的发布方式,git pull 或解包)
# git -C $APP pull

# 6) 重启 web 与 worker(两者都要)
supervisorctl restart lightmes-backend lightmes-celery lightmes-beat   # 名称按实际配置

# 7) 冒烟
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8000/openapi.json

示例中的域名、租户编码、密钥请替换成你自己的。生产环境不要把密钥写进前端代码。

容易踩的坑

alembic upgrade 报「Multiple heads」?
迁移链分叉(两个人各自建了迁移)。用 alembic merge -m "merge heads" head1 head2 生成合并迁移,再 upgrade。别用 stamp 硬压版本号,那会跳过真实的结构变更。
升级后 Celery 任务不跑了?
worker 和 beat 也要重启。它们加载的是旧代码,不同步重启会出现「web 是新逻辑、异步任务是旧逻辑」的诡异现象。
大表加索引卡了半小时?
MySQL 8 的在线 DDL 大部分场景不锁表,但不绝对。大表操作建议放在低峰,并加 ALGORITHM=INPLACE, LOCK=NONE 显式声明(不支持会直接报错而不是静默锁表)。
能跳过迁移直接改表结构对齐吗?
短期能跑,长期会炸。alembic_version 表的版本号与真实结构不一致,下次升级时迁移会按错误的假设执行,可能重复加列或删掉数据。

接着看

还有别的问题?

先看常见问题,或者在系统内提工单,我们会回。