319 lines
14 KiB
Markdown
319 lines
14 KiB
Markdown
# 数据库迁移
|
||
|
||
<cite>
|
||
**本文引用的文件**
|
||
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py)
|
||
- [backend/alembic/env.py](file://backend/alembic/env.py)
|
||
- [backend/alembic.ini](file://backend/alembic.ini)
|
||
- [backend/alembic/script.py.mako](file://backend/alembic/script.py.mako)
|
||
- [backend/app/database.py](file://backend/app/database.py)
|
||
- [backend/app/models/__init__.py](file://backend/app/models/__init__.py)
|
||
- [backend/app/models/user.py](file://backend/app/models/user.py)
|
||
- [backend/app/models/query.py](file://backend/app/models/query.py)
|
||
- [backend/app/models/citation_record.py](file://backend/app/models/citation_record.py)
|
||
- [backend/app/models/query_task.py](file://backend/app/models/query_task.py)
|
||
- [backend/app/models/subscription.py](file://backend/app/models/subscription.py)
|
||
- [backend/app/config.py](file://backend/app/config.py)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖分析](#依赖分析)
|
||
7. [性能考虑](#性能考虑)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 简介
|
||
本文件面向GEO项目的数据库迁移与版本管理,系统性说明基于Alembic的迁移框架配置与使用方式,覆盖迁移脚本生成、版本管理、数据库升级策略、初始迁移实现(含表创建、索引与约束)、迁移命令(upgrade、downgrade、autogenerate)以及生产环境最佳实践与风险控制。读者无需深入Python或SQLAlchemy即可理解并安全地执行迁移。
|
||
|
||
## 项目结构
|
||
GEO后端采用异步SQLAlchemy与Alembic进行数据库迁移管理,迁移相关代码集中在backend/alembic目录中,并通过env.py与应用模型(models)建立连接。数据库连接由应用配置提供,迁移脚本位于versions子目录中,按版本顺序命名。
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "迁移配置"
|
||
A["alembic.ini<br/>脚本位置、日志、URL等"]
|
||
B["env.py<br/>在线/离线迁移入口"]
|
||
C["script.py.mako<br/>迁移模板"]
|
||
end
|
||
subgraph "模型定义"
|
||
D["models/__init__.py<br/>导出所有模型"]
|
||
E["models/user.py"]
|
||
F["models/query.py"]
|
||
G["models/citation_record.py"]
|
||
H["models/query_task.py"]
|
||
I["models/subscription.py"]
|
||
end
|
||
subgraph "数据库"
|
||
J["PostgreSQL 实例"]
|
||
end
|
||
A --> B
|
||
B --> D
|
||
D --> E
|
||
D --> F
|
||
D --> G
|
||
D --> H
|
||
D --> I
|
||
B --> J
|
||
```
|
||
|
||
**图表来源**
|
||
- [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150)
|
||
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
|
||
- [backend/alembic/script.py.mako:1-29](file://backend/alembic/script.py.mako#L1-L29)
|
||
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
|
||
- [backend/app/models/user.py:1-41](file://backend/app/models/user.py#L1-L41)
|
||
- [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55)
|
||
- [backend/app/models/citation_record.py:1-42](file://backend/app/models/citation_record.py#L1-L42)
|
||
- [backend/app/models/query_task.py:1-39](file://backend/app/models/query_task.py#L1-L39)
|
||
- [backend/app/models/subscription.py:1-37](file://backend/app/models/subscription.py#L1-L37)
|
||
|
||
**章节来源**
|
||
- [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150)
|
||
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
|
||
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
|
||
|
||
## 核心组件
|
||
- 迁移配置与入口
|
||
- alembic.ini:定义脚本位置、日志级别、数据库URL等全局设置。
|
||
- env.py:根据运行模式(在线/离线)加载目标元数据并执行迁移。
|
||
- script.py.mako:迁移脚本模板,定义upgrade/downgrade骨架。
|
||
- 模型与元数据
|
||
- models/__init__.py:聚合导出所有ORM模型,供Alembic扫描。
|
||
- 各模型文件:定义表结构、字段类型、索引与外键关系。
|
||
- 数据库引擎
|
||
- app/database.py:创建异步引擎与Base,为迁移提供元数据基础。
|
||
- app/config.py:提供DATABASE_URL,被env.py与alembic.ini共同使用。
|
||
|
||
**章节来源**
|
||
- [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150)
|
||
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
|
||
- [backend/alembic/script.py.mako:1-29](file://backend/alembic/script.py.mako#L1-L29)
|
||
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
|
||
- [backend/app/models/user.py:1-41](file://backend/app/models/user.py#L1-L41)
|
||
- [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55)
|
||
- [backend/app/models/citation_record.py:1-42](file://backend/app/models/citation_record.py#L1-L42)
|
||
- [backend/app/models/query_task.py:1-39](file://backend/app/models/query_task.py#L1-L39)
|
||
- [backend/app/models/subscription.py:1-37](file://backend/app/models/subscription.py#L1-L37)
|
||
- [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29)
|
||
- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17)
|
||
|
||
## 架构总览
|
||
下图展示从命令到数据库的迁移执行链路,包括在线与离线两种模式,以及模型元数据对迁移的影响。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant CLI as "命令行"
|
||
participant Alembic as "Alembic CLI"
|
||
participant Env as "env.py"
|
||
participant DB as "PostgreSQL"
|
||
CLI->>Alembic : 执行迁移命令
|
||
Alembic->>Env : 加载配置与元数据
|
||
Env->>Env : 判断在线/离线模式
|
||
alt 在线模式
|
||
Env->>DB : 异步连接并执行事务
|
||
else 离线模式
|
||
Env->>DB : 使用URL直接执行DDL
|
||
end
|
||
Env-->>Alembic : 返回迁移结果
|
||
Alembic-->>CLI : 输出状态与日志
|
||
```
|
||
|
||
**图表来源**
|
||
- [backend/alembic/env.py:33-89](file://backend/alembic/env.py#L33-L89)
|
||
- [backend/alembic.ini:86-89](file://backend/alembic.ini#L86-L89)
|
||
|
||
## 详细组件分析
|
||
|
||
### 初始迁移脚本(488d0bd5ab01)
|
||
该脚本实现首次数据库初始化,包含以下要点:
|
||
- 表创建
|
||
- users:用户主表,包含唯一邮箱、计划等级、配额、激活状态等字段。
|
||
- queries:查询任务表,关联users,包含关键词、品牌、平台列表、频率、状态及时间戳。
|
||
- citation_records:引用记录表,关联queries,包含平台、是否引用、竞品品牌、原始响应等。
|
||
- query_tasks:查询任务执行表,关联queries,包含状态、错误信息与调度/开始/完成时间。
|
||
- subscriptions:订阅表,关联users,包含计划、状态、起止日期、金额与支付信息。
|
||
- 索引建立
|
||
- queries:按user_id、status、next_query_at建立索引。
|
||
- citation_records:按query_id、queried_at、platform建立索引。
|
||
- query_tasks:按status建立索引。
|
||
- 约束与默认值
|
||
- 外键约束:各子表均对父表执行级联删除。
|
||
- 默认值:广泛使用服务器默认值(如NOW()、JSONB空数组、字符串默认值)。
|
||
- 回滚策略
|
||
- downgrade按逆序删除表与索引,确保幂等与可恢复。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start(["执行初始迁移"]) --> CreateUsers["创建 users 表"]
|
||
CreateUsers --> CreateQueries["创建 queries 表<br/>建立索引"]
|
||
CreateQueries --> CreateRecords["创建 citation_records 表<br/>建立索引"]
|
||
CreateRecords --> CreateTasks["创建 query_tasks 表<br/>建立索引"]
|
||
CreateTasks --> CreateSubs["创建 subscriptions 表"]
|
||
CreateSubs --> End(["完成"])
|
||
```
|
||
|
||
**图表来源**
|
||
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:21-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L21-L128)
|
||
|
||
**章节来源**
|
||
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:1-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L1-L128)
|
||
|
||
### 迁移环境与元数据
|
||
- 元数据来源
|
||
- env.py通过app.database.Base.metadata提供目标元数据,确保Alembic能识别应用模型的变更。
|
||
- models/__init__.py统一导出所有模型,避免遗漏。
|
||
- 在线/离线模式
|
||
- 在线模式:使用异步引擎连接数据库,适合生产与容器环境。
|
||
- 离线模式:直接使用URL执行DDL,便于测试与快速验证。
|
||
- 配置来源
|
||
- DATABASE_URL来自app/config.py,同时在alembic.ini中也有默认示例URL。
|
||
|
||
```mermaid
|
||
graph LR
|
||
A["env.py"] --> B["Base.metadata"]
|
||
B --> C["models/*"]
|
||
A --> D["在线/离线执行器"]
|
||
D --> E["PostgreSQL"]
|
||
```
|
||
|
||
**图表来源**
|
||
- [backend/alembic/env.py:10-25](file://backend/alembic/env.py#L10-L25)
|
||
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
|
||
- [backend/app/database.py](file://backend/app/database.py#L20)
|
||
- [backend/app/config.py](file://backend/app/config.py#L7)
|
||
|
||
**章节来源**
|
||
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
|
||
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
|
||
- [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29)
|
||
- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17)
|
||
|
||
### 迁移命令与工作流
|
||
- 常用命令
|
||
- 升级:将数据库迁移到最新版本。
|
||
- 降级:将数据库回退到指定版本。
|
||
- 自动化生成:基于模型变更自动生成迁移脚本。
|
||
- 工作流建议
|
||
- 开发阶段:先在本地dev环境验证,再合并到测试环境。
|
||
- 测试阶段:在隔离数据库上执行,验证数据完整性与索引有效性。
|
||
- 生产阶段:严格遵循“只读优先”原则,先备份,再执行,最后验证。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Dev["开发环境"] --> Test["测试环境"]
|
||
Test --> Prod["生产环境"]
|
||
Dev --> |dry-run/验证| Test
|
||
Test --> |备份/演练| Prod
|
||
```
|
||
|
||
[本节为通用流程说明,不直接分析具体文件,故无“章节来源”]
|
||
|
||
### 数据保护、回滚与版本控制
|
||
- 数据保护
|
||
- 在生产环境执行前务必备份数据库。
|
||
- 对大表操作(如重建索引)选择维护窗口,避免高峰时段。
|
||
- 回滚机制
|
||
- 初始迁移提供完整的downgrade路径,确保可逆。
|
||
- 建议每次迁移仅包含单一逻辑变更,降低回滚复杂度。
|
||
- 版本控制
|
||
- 迁移脚本以版本号命名,保持顺序与可追溯性。
|
||
- 将迁移脚本纳入版本控制系统,配合提交信息描述变更意图。
|
||
|
||
**章节来源**
|
||
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:114-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L114-L128)
|
||
|
||
### 生产环境最佳实践与风险控制
|
||
- 风险控制
|
||
- 限制迁移窗口,避免业务高峰期。
|
||
- 使用只读副本或独立测试库先行验证。
|
||
- 对DDL操作进行分批执行,逐步替换索引与约束。
|
||
- 可观测性
|
||
- 记录迁移日志,监控执行时长与失败原因。
|
||
- 在应用侧增加迁移状态检查,防止未完成迁移导致的数据不一致。
|
||
- 安全与合规
|
||
- 严格管理DATABASE_URL与访问权限。
|
||
- 对敏感字段(如密码哈希)迁移需遵循最小暴露原则。
|
||
|
||
**章节来源**
|
||
- [backend/alembic.ini:115-150](file://backend/alembic.ini#L115-L150)
|
||
- [backend/alembic/env.py:33-89](file://backend/alembic/env.py#L33-L89)
|
||
|
||
## 依赖分析
|
||
- 组件耦合
|
||
- env.py依赖app/config.py提供的DATABASE_URL与app/database.py的Base元数据。
|
||
- models/__init__.py集中导出所有模型,提升扫描效率与一致性。
|
||
- 外部依赖
|
||
- PostgreSQL作为目标数据库,UUID、JSONB、时间戳等类型在迁移脚本中被广泛使用。
|
||
- 潜在问题
|
||
- 若models/__init__.py遗漏导出,可能导致autogenerate无法识别新模型。
|
||
- 在线迁移依赖异步引擎,需确保网络与连接池配置正确。
|
||
|
||
```mermaid
|
||
graph TB
|
||
Env["env.py"] --> Cfg["app/config.py"]
|
||
Env --> DB["app/database.py"]
|
||
DB --> Meta["Base.metadata"]
|
||
Meta --> Models["models/*"]
|
||
```
|
||
|
||
**图表来源**
|
||
- [backend/alembic/env.py:10-25](file://backend/alembic/env.py#L10-L25)
|
||
- [backend/app/config.py](file://backend/app/config.py#L7)
|
||
- [backend/app/database.py](file://backend/app/database.py#L20)
|
||
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
|
||
|
||
**章节来源**
|
||
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
|
||
- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17)
|
||
- [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29)
|
||
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
|
||
|
||
## 性能考虑
|
||
- 索引设计
|
||
- 初始迁移已为高频查询字段建立索引,有助于提升查询性能。
|
||
- 对于大表,建议在维护窗口内重建索引,避免阻塞。
|
||
- 迁移窗口
|
||
- 将DDL密集型操作安排在低峰时段,减少对线上服务的影响。
|
||
- 幂等性
|
||
- 迁移脚本应具备幂等特性,避免重复执行造成资源浪费。
|
||
|
||
**章节来源**
|
||
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:57-94](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L57-L94)
|
||
|
||
## 故障排查指南
|
||
- 常见问题
|
||
- 迁移失败:检查DATABASE_URL是否正确,确认数据库可达。
|
||
- 模型未识别:确保models/__init__.py导出了新增模型。
|
||
- 在线/离线模式混淆:确认运行环境与配置文件一致。
|
||
- 排查步骤
|
||
- 查看日志:调整alembic.ini中的日志级别以获取更详细输出。
|
||
- 回滚验证:使用downgrade验证回滚路径是否完整。
|
||
- 数据核对:迁移完成后执行简单查询,核对关键索引与约束是否生效。
|
||
|
||
**章节来源**
|
||
- [backend/alembic.ini:115-150](file://backend/alembic.ini#L115-L150)
|
||
- [backend/alembic/env.py:33-89](file://backend/alembic/env.py#L33-L89)
|
||
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:114-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L114-L128)
|
||
|
||
## 结论
|
||
GEO项目已建立完善的Alembic迁移体系:清晰的配置、可靠的元数据扫描、完备的初始迁移脚本与回滚路径。遵循本文的命令使用方法、最佳实践与风险控制措施,可在保障数据安全的前提下高效推进数据库演进。
|
||
|
||
## 附录
|
||
- 迁移命令速查
|
||
- 升级到最新:alembic upgrade head
|
||
- 降级到上一版本:alembic downgrade -1
|
||
- 降级到指定版本:alembic downgrade <版本号>
|
||
- 自动生成迁移:alembic revision --autogenerate -m "<描述>"
|
||
- 关键文件定位
|
||
- 配置:backend/alembic.ini
|
||
- 环境:backend/alembic/env.py
|
||
- 模板:backend/alembic/script.py.mako
|
||
- 初始迁移:backend/alembic/versions/488d0bd5ab01_initial_migration.py
|
||
- 模型聚合:backend/app/models/__init__.py
|
||
- 数据库配置:backend/app/config.py |