【问题标题】:flyway: forcing migrations even if a SQL statement failedflyway:即使 SQL 语句失败也强制迁移
【发布时间】:2012-05-17 03:57:36
【问题描述】:

我为工作中的应用程序创建了一个 flyway 项目。事实证明,在我准备好 flyway 设置以进行测试之前,其中一位开发人员已经在 TEST 上执行了一些 SQL 语句。

我的sql脚本有几条语句:

ALTER TABLE "TABLE1" MODIFY ("NAME" VARCHAR2(75 CHAR));
ALTER TABLE "TABLE2" DROP ("BOARD_ID");
ALTER TABLE "TABLE3" ADD CONSTRAINT "SYS_C0022270" CHECK ("ID" IS NOT NULL) ENABLE;

应该在语句 #2 中删除的列已经在我们的 TEST 实例上手动删除。它尚未在我们的 PROD 实例上删除,我想通过迁移而不是手动来完成。

显然,如果不先在 TEST 上进行尝试,我不会在 PROD 上运行迁移(比这三个查询要多得多)。

但由于我遇到问题的迁移是排在第一位的,因此无法继续。

有什么办法可以强制通过吗?我知道该列已被删除。我可以再次创建它,然后让迁移将其删除。但是我可能还有其他可能失败的查询(创建可能已经存在的种子数据等)。我不希望这会阻止我们的部署。

除了再次从 PROD 克隆我们的数据库并让开发团队在我准备一组新的迁移时停止他们的开发之外,还有其他想法吗?

【问题讨论】:

    标签: oracle migration flyway


    【解决方案1】:

    您可以将任何您想忽略错误的 SQL 语句放入带有异常处理程序的 PL/SQL 块中:

    BEGIN 
      EXECUTE IMMEDIATE 'ALTER TABLE "TABLE1" MODIFY ("NAME" VARCHAR2(75 CHAR))';
    EXCEPTION
      WHEN OTHERS THEN
        -- perhaps print a message about the command failure here
    END;
    /
    

    DDL 必须在 PL/SQL 的立即执行语句中完成。

    有点痛,但应该可以。

    【讨论】:

    • 谢谢!这确实有效。唯一的问题是 flyway 似乎没有返回任何“DBMS_OUTPUT.PUT_LINE()”返回。我将使用 sqlplus 编写一些简单的脚本,在我们即将发布的版本之后重新克隆我们的 PROD 数据库并重新开始。
    • 您也可以使用 utl_file 将您的消息写入文件。
    【解决方案2】:

    听起来,重新创建列听起来确实是最佳解决方案。

    它超级简单,如果唯一的目的是让列之后立即再次删除,绝对无害。

    除非我错过了故事的一部分,否则我无法理解未来的种子数据创建会如何与此发生冲突。

    长期的解决方案当然是改变开发文化并完全禁止手动更改数据库。

    【讨论】:

    • 给你一个种子数据冲突的例子:我们有一些对象指向存储在数据库中的 jasper 模板。不止一条记录指向该模板。每个对象的 SQL 脚本都有一个查询来创建模板,以防模板不存在。 (因为在开发时不知道首先部署哪个对象)。第一个脚本运行后,所有其他脚本都会因为一个我们并不真正关心的查询而失败,因为它已经被插入。
    • 我知道我们应该从每个文件中删除查询,并使其成为一个独立的脚本。但是忽略失败查询的方法也可以。现在,由于我们的独特需求,我不建议您实现这样的功能。我只是想知道是否有类似的东西。
    • 这与丢弃的列有什么关系?或者这只是众多例子中的一个?
    • 好的,我明白了。不,目前框架中没有内置这样的功能。对于您的情况,其他一些答案可能是很好的解决方法(即使它们正在解决症状而不是根本原因)
    • 丢弃的列故障只是非关键故障的一个示例。同样,由于存在而无法插入的记录也不是我们想要停止迁移的东西。
    【解决方案3】:

    如果您使用 sqlplus 来运行您的脚本,那么您可以在开头添加以下语句:

    WHENEVER SQLERROR CONTINUE
    

    【讨论】:

    • 这不起作用:ORA-00900: invalid SQL statement。我猜这只是 SQL*Plus 的构造。
    【解决方案4】:

    当 SQLERROR CONTINUE 和 DBMS_OUTPUT.PUT_LINE() 不适用于 flyway,它是特定于 SQLPLUS 客户端的,您可以使用 RAISE

    EXCEPTION
    
    WHEN OTHERS THEN
    
    DBMS_OUTPUT.PUT_LINE(SQLERRM || CHR(10) ||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    
    ROLLBACK;
    
    Raise_Application_Error (-20000, SQLERRM || ' : ' ||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    
    END;
    

    Flyway 将停止迁移过程并在日志中打印问题。

    如果您想继续迁移,请不要用户提出而是另一种打印解决方案。 使用 flyway 4.0.3 测试

    【讨论】:

      猜你喜欢
      • 2013-03-05
      • 2019-01-16
      • 2017-03-23
      • 2020-05-24
      • 2020-02-25
      • 2019-09-13
      • 2012-08-09
      • 2014-08-02
      • 2012-07-21
      相关资源
      最近更新 更多