You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7.5 KiB
7.5 KiB
数据库迁移问题根因分析与解决方案
日期: 2026-02-14
问题: 反复遇到数据库迁移失败
影响: 应用无法启动,API 返回 500 错误
🔍 根本原因
核心问题:不规范的迁移文件创建方式
项目中存在两种迁移文件格式混用,导致迁移链混乱:
❌ 手动创建(错误方式)
# 文件名: 20260214_1214_add_thumbnail_url_to_storyboard_videos.py
revision = '20260214_1214' # 使用时间戳作为 revision ID
down_revision = '7b87dd948cd7'
问题:
- ❌ revision ID 不唯一,容易重复
- ❌ 与 Alembic 标准不兼容
- ❌ 迁移链容易断裂
- ❌ 难以追踪和调试
✅ Alembic 自动生成(正确方式)
# 文件名: 20260205_1149_2f908ad1a28d_add_missing_table_comments.py
revision: str = '2f908ad1a28d' # 12位随机哈希
down_revision: Union[str, None] = 'ddc84535ab31'
优点:
- ✅ revision ID 唯一且随机
- ✅ 符合 Alembic 标准
- ✅ 自动管理迁移链
- ✅ 易于追踪和回滚
📊 问题统计
检查发现项目中的迁移文件格式:
$ grep "^revision = " *.py | wc -l
非标准格式:约 18 个文件使用时间戳或描述性名称作为 revision ID
标准格式:仅 5 个文件使用 Alembic 生成的哈希 ID
✅ 解决方案
立即修复(应急方案)
当遇到迁移失败时:
# 1. 完全重建容器和数据库
cd server
./start_docker.sh -c -b
# 2. 等待启动完成
sleep 30
# 3. 验证迁移状态
docker exec jointo-server-app alembic current
# 4. 测试 API
curl http://localhost:6170/api/health
长期解决(规范化)
1. 禁止手动创建迁移文件
错误示例:
# ❌ 不要这样做
touch alembic/versions/20260214_1214_add_field.py
# 然后手动编辑内容
正确方式:
# ✅ 始终使用 Alembic 命令
docker exec jointo-server-app alembic revision -m "add thumbnail_url to storyboard_videos"
# 或使用 autogenerate(推荐)
docker exec jointo-server-app alembic revision --autogenerate -m "add thumbnail_url"
2. 迁移文件创建流程
# Step 1: 修改 Model 文件
# 编辑 app/models/storyboard_resource.py
# Step 2: 生成迁移文件
docker exec jointo-server-app alembic revision --autogenerate -m "描述你的变更"
# Step 3: 检查生成的迁移文件
# 查看 alembic/versions/ 下最新的文件
# Step 4: 如有必要,手动调整迁移内容
# 但不要修改 revision 和 down_revision
# Step 5: 执行迁移
docker exec jointo-server-app alembic upgrade head
# Step 6: 验证
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d storyboard_videos"
3. 现有迁移文件的修复计划
不建议修改现有迁移:已经执行过的迁移不应修改,会导致更多问题。
推荐方案:
- 保持现有迁移文件不变
- 新的迁移严格使用 Alembic 生成
- 在项目文档中记录这个历史遗留问题
- 定期备份数据库
📋 最佳实践
开发流程规范
添加新字段
# 1. 修改 Model
class StoryboardVideo(SQLModel, table=True):
# ... 现有字段 ...
thumbnail_url: Optional[str] = Field(
default=None,
max_length=500,
sa_column_kwargs={"comment": "缩略图URL(视频第一帧)"}
)
# 2. 生成迁移
$ docker exec jointo-server-app alembic revision --autogenerate -m "add thumbnail_url to storyboard_videos"
# 3. 检查生成的文件
# alembic/versions/20260214_1310_abc123def456_add_thumbnail_url_to_storyboard_videos.py
# 4. 执行迁移
$ docker exec jointo-server-app alembic upgrade head
删除字段
# 1. 从 Model 中删除字段
# 2. 生成迁移
$ docker exec jointo-server-app alembic revision --autogenerate -m "remove obsolete_field"
# 3. 手动编辑迁移文件,确保 downgrade() 能恢复数据
def downgrade() -> None:
op.add_column('table_name', sa.Column('obsolete_field', ...))
# 4. 执行迁移
$ docker exec jointo-server-app alembic upgrade head
修改字段
# 1. 修改 Model 字段定义
# 2. 生成迁移
$ docker exec jointo-server-app alembic revision --autogenerate -m "change field_name type"
# 3. **重要**:检查生成的迁移,autogenerate 可能无法检测某些变更
# 必要时手动添加 ALTER COLUMN 语句
# 4. 执行迁移
$ docker exec jointo-server-app alembic upgrade head
迁移测试流程
每次创建迁移后,必须测试:
# 1. 测试 upgrade
docker exec jointo-server-app alembic upgrade head
# 2. 测试 downgrade
docker exec jointo-server-app alembic downgrade -1
# 3. 再次 upgrade(确保可以重复执行)
docker exec jointo-server-app alembic upgrade head
# 4. 在干净环境测试(最重要!)
./start_docker.sh -c -b # 完全重建
# 等待启动,查看日志确认迁移成功
🚫 常见错误
错误 1:手动创建迁移文件
# ❌ 错误
vi alembic/versions/add_new_field.py
# ✅ 正确
docker exec jointo-server-app alembic revision -m "add new field"
错误 2:修改已执行的迁移
# ❌ 错误:修改已经执行过的迁移文件
# alembic/versions/20260213_1840_xxx.py
revision = '20260213_1840' # 已经在数据库中记录
# 然后修改 upgrade() 内容
# ✅ 正确:创建新的迁移
docker exec jointo-server-app alembic revision -m "fix previous migration"
错误 3:忘记删除 pycache
# 删除文件后必须清理缓存
rm alembic/versions/some_migration.py
rm -rf alembic/versions/__pycache__/
docker restart jointo-server-app
错误 4:不测试干净环境
# ❌ 错误:只在现有数据库测试
docker exec jointo-server-app alembic upgrade head
# 看起来成功了!
# ✅ 正确:在干净环境测试
./start_docker.sh -c -b
# 确认从零开始能完整执行所有迁移
🛠️ 调试工具
查看迁移历史
# 查看当前版本
docker exec jointo-server-app alembic current
# 查看迁移历史
docker exec jointo-server-app alembic history
# 查看详细历史
docker exec jointo-server-app alembic history --verbose
# 查看所有 head
docker exec jointo-server-app alembic heads
检查迁移链
# 检查是否有分支
docker exec jointo-server-app alembic branches
# 检查未应用的迁移
docker exec jointo-server-app alembic show head
数据库检查
# 查看所有表
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\dt"
# 查看表结构
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d storyboard_videos"
# 查看迁移版本记录
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "SELECT * FROM alembic_version;"
📚 相关文档
🎯 总结
问题根源
混合使用手动创建和 Alembic 生成的迁移文件,导致迁移链混乱
解决方案
- ✅ 永远使用
alembic revision命令生成迁移 - ✅ 不要手动创建或修改 revision ID
- ✅ 每次迁移后在干净环境测试
- ✅ 定期清理 pycache
紧急恢复
./start_docker.sh -c -b
遵循这些规范,可以避免 99% 的迁移问题!