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.
 

3.5 KiB

修复数据库迁移脚本 - 废弃表引用问题

类型: Bug 修复
日期: 2026-02-14
影响范围: 数据库迁移系统

问题描述

数据库初始化失败,错误信息:

relation "screenplay_characters" does not exist

应用启动时迁移执行报错,导致所有需要数据库的 API 返回 500 错误。

根本原因

  1. 重复迁移文件:存在两个相同 revision ID 的迁移文件

    • 20260214_1214_add_thumbnail_url_to_storyboard_videos.py
    • 20260214_1214_d1446f0f5918_add_thumbnail_url_to_storyboard_videos.py
  2. 废弃表引用:迁移 20260205_1156_72966791b2f1_fix_time_fields_functions_and_triggers.py 尝试为已废弃的表创建触发器

    • drop_screenplay_tables 迁移删除了 screenplay_charactersscreenplay_locationsscreenplay_props 三张表
    • 20260205_1156 仍在尝试为这些表创建 updated_at 触发器

解决方案

1. 删除重复迁移文件

删除了重复的迁移文件:

rm server/alembic/versions/20260214_1214_d1446f0f5918_add_thumbnail_url_to_storyboard_videos.py
rm -rf server/alembic/versions/__pycache__/

2. 修复迁移脚本

修改 20260205_1156_72966791b2f1_fix_time_fields_functions_and_triggers.py

变更内容

  • 在创建触发器前添加表存在性检查
  • 从触发器列表中移除废弃的三张表
  • 更新 trigger_name 判断条件,移除废弃表的引用

upgrade() 函数修改

for table in tables_with_updated_at:
    # 检查表是否存在(screenplay_* 表可能已被删除)
    conn = op.get_bind()
    result = conn.execute(sa.text(f"""
        SELECT EXISTS (
            SELECT FROM information_schema.tables 
            WHERE table_schema = 'public' 
            AND table_name = '{table}'
        );
    """))
    table_exists = result.scalar()
    
    if not table_exists:
        print(f"  ⚠️  跳过不存在的表: {table}")
        continue
    
    # 只为 project_resources 和 screenplays 使用 trigger_ 前缀
    trigger_name = f"update_{table}_updated_at"
    if table in ['project_resources', 'screenplays']:
        trigger_name = f"trigger_update_{table}_updated_at"
    
    # ... 创建触发器 ...

downgrade() 函数同步修改

测试结果

迁移执行成功

$ docker exec jointo-server-app alembic current
20260214_1214 (head)

API 正常响应

$ curl http://localhost:6170/api/v1/users/me \
  -H 'Authorization: Bearer xxx'
  
{
  "success": false,
  "code": 401,
  "message": "无效的认证凭证或 Token 已过期",
  "data": null,
  "timestamp": "2026-02-14T05:05:20.037199+00:00"
}

返回 401 认证错误(业务逻辑正常),不再是 500 服务器错误。

涉及文件

修改

  • server/alembic/versions/20260205_1156_72966791b2f1_fix_time_fields_functions_and_triggers.py

删除

  • server/alembic/versions/20260214_1214_d1446f0f5918_add_thumbnail_url_to_storyboard_videos.py

后续建议

  1. 迁移文件命名规范:避免手动创建迁移文件,统一使用 alembic revision 命令生成
  2. 定期清理:定期清理 __pycache__ 目录,避免缓存旧版本
  3. 迁移测试:重大迁移前在干净容器中测试,确保从头开始的迁移链完整
  4. 废弃表清理:删除表前检查是否有其他迁移引用该表

相关文档

  • ADR 006: TIMESTAMPTZ 时间戳规范
  • 迁移指南: docs/server/guides/database-migration.md