多数据库迁移的艺术:Alembic在复杂环境中的精妙应用

avatar
cmdragon 大乘
image image

扫描二维码
关注或者微信搜一搜:编程智域 前端至全栈交流与成长

探索数千个预构建的 AI 应用,开启你的下一个伟大创意https://tools.cmdragon.cn/

  1. 多数据库环境下的迁移需求分析
    现代Web应用中常见以下多数据库场景:
  • 主从数据库架构(读写分离)
  • 多租户系统(不同租户使用独立数据库)
  • 混合数据库类型(MySQL+PostgreSQL组合使用)
  • 分库分表架构(水平拆分业务模块)
  1. Alembic多数据库配置方法
    创建多版本目录结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
project/
├── alembic/
│ ├── versions/
│ │ ├── db1/
│ │ └── db2/
│ └── env.py
├── alembic.ini
└── app/
└── models.py
```

修改alembic.ini配置:

```ini
[alembic]
script_location = alembic

[db1]
sqlalchemy.url = postgresql://user:pass@localhost/db1

[db2]
sqlalchemy.url = mysql://user:pass@localhost/db2
```

环境脚本改造(env.py):

```python
from alembic import context


def run_migrations(engine_name):
config = context.config
section = config.get_section(engine_name)
url = section["sqlalchemy.url"]

engine = create_engine(url)
with engine.connect() as connection:
context.configure(
connection=connection,
target_metadata=get_metadata(engine_name),
version_table=f'alembic_version_{engine_name}'
)
with context.begin_transaction():
context.run_migrations(engine_name)


if context.is_offline_mode():
run_migrations('db1')
run_migrations('db2')
else:
for engine_name in ['db1', 'db2']:
run_migrations(engine_name)
```

3. 模型定义最佳实践
使用pydantic结合SQLAlchemy ORM:

```python
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel


class UserBase(BaseModel):
email: str
is_active: bool = True


class UserCreate(UserBase):
password: str


class UserDB(UserBase):
id: int


Db1Base = declarative_base()
Db2Base = declarative_base()


class Db1User(Db1Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
email = Column(String)
password_hash = Column(String)
is_active = Column(Boolean)


class Db2Log(Db2Base):
__tablename__ = "logs"
id = Column(Integer, primary_key=True)
action = Column(String)
user_id = Column(Integer)
```

4. 多数据库迁移操作指南
生成独立迁移脚本:

```bash
alembic -n db1 revision --autogenerate -m "add users table"
alembic -n db2 revision --autogenerate -m "add logs table"
```

执行迁移命令:

```bash
alembic -n db1 upgrade head
alembic -n db2 upgrade head
```

查看迁移历史:

```bash
alembic -n db1 history --verbose
alembic -n db2 history --verbose
```

5. 课后Quiz
Q1:当需要为第三个数据库添加迁移支持时,应该修改哪些配置文件?
A) 只需修改alembic.ini
B) 修改env.py和alembic.ini
C) 修改models.py和env.py
D) 需要创建新的版本目录并修改所有配置文件

正确答案:B
解析:需要修改alembic.ini添加新的数据库配置段落,并在env.py中扩展迁移执行逻辑。模型定义可能需要新增基类,但不需要修改现有文件。

Q2:如何为不同数据库设置独立的迁移版本表?
A) 在模型类中指定__version_table__属性
B) 在env.py的context.configure中设置version_table参数
C) 修改alembic.ini的version_table配置项
D) 使用不同的迁移目录结构

正确答案:B
解析:context.configure()中的version_table参数允许为每个数据库引擎指定独立的版本表名称。

6. 常见报错解决方案
错误1:`sqlalchemy.exc.NoSuchTableError: alembic_version`
原因:目标数据库未初始化迁移版本表
解决:

```bash
alembic -n db1 revision --autogenerate --version-path=alembic/versions/db1
alembic -n db1 stamp head
```

错误2:`KeyError: 'No such section: 'db3'`
原因:alembic.ini缺少对应数据库配置
解决:

```ini
[db3]
sqlalchemy.url = sqlite:///db3.sqlite
```

错误3:`SAWarning: Class <class 'app.models.Db1User'> does not have a __table__`
原因:模型类未正确绑定到元数据
解决:

```python
Db1Base.metadata.create_all(engine) # 在应用启动时执行

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:

往期文章归档: