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.3 KiB
7.3 KiB
初始化数据库迁移系统
日期: 2026-01-27
类型: 数据库迁移
影响范围: 全新环境部署
概述
创建完整的初始化数据库迁移脚本,支持全新环境一键创建所有表结构。
背景
之前的基线迁移(baseline)只是标记现有数据库状态,不包含实际的建表逻辑。这导致全新环境部署时无法自动创建表结构。
变更内容
1. 删除旧基线迁移
删除文件:
server/alembic/versions/20260127_1412_dc0e4f0a740c_baseline_标记现有数据库状态.py
2. 生成完整初始化迁移
新文件:
server/alembic/versions/20260127_1931_3a3a2a1417de_initial_schema_初始化所有表结构.py- 迁移版本:
3a3a2a1417de
包含所有表的完整建表逻辑:
- ✅ 用户系统(users, user_sessions)
- ✅ 文件夹系统(folders, folder_members)
- ✅ 项目系统(projects, project_members, project_shares, project_versions)
- ✅ AI 服务(ai_models, ai_jobs, ai_quotas, ai_usage_logs)
- ✅ 积分系统(credit_transactions, credit_consumption_logs, credit_gifts, credit_packages, credit_pricing)
- ✅ 充值系统(recharge_orders, payment_callbacks)
- ✅ 短信服务(sms_verification_codes)
3. 自动创建 UUID v7 函数
迁移脚本在 upgrade() 函数开头自动创建 UUID v7 函数:
def upgrade() -> None:
"""升级数据库"""
# 1. 创建 UUID v7 函数(必须在创建表之前)
op.execute("""
CREATE OR REPLACE FUNCTION gen_uuid_v7() RETURNS uuid AS $$
DECLARE
unix_ts_ms BIGINT;
uuid_bytes BYTEA;
BEGIN
unix_ts_ms = (EXTRACT(EPOCH FROM CLOCK_TIMESTAMP()) * 1000)::BIGINT;
uuid_bytes = SUBSTRING(INT8SEND(unix_ts_ms) FROM 3 FOR 6) || gen_random_bytes(10);
RETURN ENCODE(
SET_BYTE(SET_BYTE(uuid_bytes, 6, (GET_BYTE(uuid_bytes, 6) & 15) | 112), 8, (GET_BYTE(uuid_bytes, 8) & 63) | 128),
'hex'
)::UUID;
END;
$$ LANGUAGE plpgsql VOLATILE;
""")
# 2. 创建所有表结构
# ...
在 downgrade() 函数结尾自动删除:
def downgrade() -> None:
"""回滚数据库"""
# 删除所有表...
# 3. 删除 UUID v7 函数
op.execute("DROP FUNCTION IF EXISTS gen_uuid_v7()")
4. 修复枚举值问题
修复了 server/app/models/recharge/order.py 中的索引定义:
- 问题: 索引条件中使用了枚举对象
PaymentStatus.PENDING - 修复: 改为整数值
1(PENDING 的枚举值) - 原因: Alembic autogenerate 无法将枚举对象渲染为 SQL 字面值
# 修复前
Index('idx_recharge_orders_payment_status_pending', 'payment_status',
postgresql_where=Column('payment_status') == PaymentStatus.PENDING)
# 修复后
Index('idx_recharge_orders_payment_status_pending', 'payment_status',
postgresql_where=Column('payment_status') == 1) # 1 = PENDING
4. 修复枚举值问题
- ✅ 禁止外键约束(应用层验证)
- ✅ 枚举类型使用 SMALLINT
- ✅ UUID v7 主键
- ✅ 时间戳字段(created_at, updated_at, deleted_at)
- ✅ 索引优化
部署指南
全新环境部署
# 1. 启动容器(自动执行迁移)
./start_docker.sh --clean --build
⚠️ 注意:
- 脚本会自动检测首次部署并执行数据库迁移
- 迁移脚本会自动创建 UUID v7 函数和所有表
- 迁移成功后会创建标记文件
.migration_initialized
现有环境更新
如果你的数据库已经有表结构:
# 标记为已应用最新迁移(不执行建表)
docker exec jointo-server-app alembic stamp head
# 验证
docker exec jointo-server-app alembic current
验证结果
检查迁移状态
$ docker exec jointo-server-app alembic current
3a3a2a1417de (head)
检查表结构
$ docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\dt"
List of relations
Schema | Name | Type | Owner
--------+-------------------------+-------+----------
public | ai_jobs | table | jointoAI
public | ai_models | table | jointoAI
public | ai_quotas | table | jointoAI
public | ai_usage_logs | table | jointoAI
public | alembic_version | table | jointoAI
public | credit_consumption_logs | table | jointoAI
public | credit_gifts | table | jointoAI
public | credit_packages | table | jointoAI
public | credit_pricing | table | jointoAI
public | credit_transactions | table | jointoAI
public | folder_members | table | jointoAI
public | folders | table | jointoAI
public | payment_callbacks | table | jointoAI
public | project_members | table | jointoAI
public | project_shares | table | jointoAI
public | project_versions | table | jointoAI
public | projects | table | jointoAI
public | recharge_orders | table | jointoAI
public | sms_verification_codes | table | jointoAI
public | user_sessions | table | jointoAI
public | users | table | jointoAI
(21 rows)
优势
1. 全新环境支持
- ✅ 一键创建所有表结构
- ✅ 无需手动执行 SQL
- ✅ 自动应用索引和约束
2. 版本化管理
- ✅ 完整的迁移历史
- ✅ 支持 upgrade 和 downgrade
- ✅ 自动依赖管理
3. 团队协作
- ✅ 统一的数据库结构
- ✅ 可重复的部署流程
- ✅ 易于代码审查
注意事项
1. 现有环境
如果你的数据库已经有表结构,不要执行 alembic upgrade,而是使用 alembic stamp head 标记为已应用。
2. 数据备份
在生产环境执行迁移前,务必备份数据库:
docker exec jointo-server-postgres pg_dump -U jointoAI jointo > backup_$(date +%Y%m%d_%H%M%S).sql
3. 迁移测试
在开发环境测试迁移的 upgrade 和 downgrade:
# 测试升级
docker exec jointo-server-app alembic upgrade head
# 测试回滚
docker exec jointo-server-app alembic downgrade base
# 重新升级
docker exec jointo-server-app alembic upgrade head
相关文档
问题排查
问题 1:表已存在
症状:执行 alembic upgrade 时报错 "relation already exists"
解决:使用 alembic stamp head 标记为已应用
问题 2:迁移版本不一致
症状:alembic current 显示旧版本或无版本
解决:
# 查看当前版本
docker exec jointo-server-app alembic current
# 标记为最新版本
docker exec jointo-server-app alembic stamp head
问题 3:容器未运行
症状:命令执行失败
解决:
# 启动容器
docker compose up -d
# 检查容器状态
docker ps | grep jointo-server
总结
完成了从标记式基线迁移到完整初始化迁移的转换,现在支持:
- ✅ 全新环境一键部署
- ✅ 现有环境平滑升级
- ✅ 完整的版本化管理
- ✅ 符合 Jointo 技术栈规范