python - 进行 Alembic 升级的试运行
问题描述
有时alembic upgrade head
可能会在运行时对我的生产数据库失败,即使它对我的测试数据库运行良好。例如,迁移可能会向以前在我的测试环境中不包含 s 但在生产中包含 sNOT NULL
的列添加约束。NULL
NULL
在规划部署时,最好能够在运行迁移之前检查它是否能够干净地应用。这对于不支持事务 DDL(在事务中更改模式)的数据库(如 MySQL)来说可能是不可能的,但原则上对于支持事务 DDL 的数据库(如 PostgreSQL)应该是可能的;Alembic 可以尝试在事务中执行升级,然后回滚。
(一个警告:这是一个不完美的解决方案,因为 PostgreSQL 允许一些约束是DEFERRED
,这意味着在您提交之前不会检查它们。我想,如果不创建数据库副本,检查这些是不可能的。但是尽管如此,执行 DDL 和回滚方法总比没有好。)
Alembic 是否支持此类功能?如果没有,是否有一些 hacky 方法来实现它?
解决方案
实现这一点的一个简单技巧是将条件回滚注入run_migrations_online
函数中,该函数env.py
仅在存在表示我们想要空运行的标志时触发。
run_migrations_online
如果你的已经被修改了,请回忆一下创建的函数的默认实现,alembic init
如下所示:
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
注意:
- 的
__enter__
方法context.begin_transaction()
- 我们已经在默认实现中调用 - 给我们一个带有rollback()
方法的事务对象,如果后端使用事务 DDL,或者如果事务 ddl 被强制使用 transactional_ddl 标志,并且 - 我们的
context
对象有一个get_x_argument
方法,我们可以使用它来支持将自定义参数传递给alembic
命令。
因此,通过以下小的更改(除了添加as transaction
最后三行之外,下面的所有内容都是相同的)我们可以拥有我们的试运行功能:
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
# ensure the context will create a transaction
# for backends that dont normally use transactional DDL.
# note that ROLLBACK will not roll back DDL structures
# on databases such as MySQL, as well as with SQLite
# Python driver's default settings
transactional_ddl=True,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction() as transaction:
context.run_migrations()
if 'dry-run' in context.get_x_argument():
print('Dry-run succeeded; now rolling back transaction...')
transaction.rollback()
现在,要进行试运行,请执行以下操作:
alembic -x dry-run upgrade head
要真正运行,只需执行以下操作:
alembic upgrade head
就像之前一样。
推荐阅读
- php - 数组变量未从 while 循环中打印出来
- javascript - 再次单击按钮后如何显示警报?
- c# - 带有 js 的 asp.net 网络表单
- excel - 如何过滤数据透视表以仅包含 2019 年的日期(多选)
- python - 使用 IPv6 的 uPNP / ssdp 发现
- azure - 有没有办法通过 Microsoft Graph-Api 撤销 Azure Active Directory 应用程序同意
- api - 在受限环境中使用移动应用程序保护 API 访问
- mysql - 上传文件(照片),将其作为字符串保存到本地文件夹(到数据库)并从特定文件夹显示为 jpg
- apache-spark - Spark:scala中数据集的动态过滤器
- kubernetes - 单个 HPA 的 K8S 纵向扩展延迟