9

我正在尝试使用带有 MySQL 引擎的 alembic 来执行在线迁移。我发现当我的 onupgrade() 方法中的操作失败时,我的数据库会陷入不一致的状态,直到我手动清理在 onupgrade() 失败之前发生的任何操作之前,我才能使用 alembic

例子:

def upgrade():
    op.create_table('sometable',
            Column('id', INTEGER, primary_key=True),
            Column('name', VARCHAR(150), nullable=False, unique=True))
    op.add_column('anothertable' Column('id', INTEGER))
    op.create_table('secondtable')

因此,如果我运行它并且 op.add_column 失败,即使我修复了 add_column 行,现在“sometable”也存在,所以第一个操作总是会失败。我无法运行我的降级脚本,因为 alembic 从未更新过版本,因为它没有完成升级。

我在想是否有办法强制运行我的 ondowngrade(),这可能很有用。我不得不忽略错误,因为肯定会有一些错误。就像放弃“secondtable”一样。我无论如何都找不到这样做。

任何人有一个很好的方法来处理这个?

4

2 回答 2

8

问题不在于 alembic,而在于您对 MySQL 的使用,它无法回滚 DDL 语句。

因此,实现它的唯一(丑陋)方法是进行手动异常处理并反转在此之前成功的操作。

像这样的东西(写在我的脑海里,所以它不是最优雅的解决方案,甚至可能有点错误,但我希望你明白要点):

def upgrade():
    try:
        op.create_table('sometable',
            Column('id', INTEGER, primary_key=True),
            Column('name', VARCHAR(150), nullable=False, unique=True))
    except:
        try:
            op.drop_table('sometable')
        except:
            pass
        raise

    try:
        op.add_column('anothertable' Column('id', INTEGER))
    except:
        op.drop_table('sometable')
        try:
            op.drop_column('anothertable', 'id')
        except:
            pass
        raise

    try:
        op.create_table('secondtable')
    except:
        op.drop_table('sometable')
        op.drop_column('anothertable', 'id')
        try:
            op.drop_table('secondtable')
        except:
            pass
        raise
于 2013-07-28T06:56:23.000 回答
2

如果您对要从中迁移的数据库模型进行版本控制,则可以临时使用它来创建迁移。(您可能必须清空您的版本文件夹/将所有内容放在临时目录中)Alembic 会将数据库的当前状态与模型进行比较,并为您提供数据库迁移命令以达到该状态。在这种情况下,它应该为您提供将数据库恢复到以前状态的说明。您必须查看生成的迁移命令,以确保它正是您需要的,但您不需要自己生成它们。

之后,您可以删除迁移,并回滚到最新的 db 模型文件。然后你应该回到你开始的地方

于 2015-10-01T23:06:38.917 回答