flyway:即使 SQL 语句失败也强制迁移

Posted

技术标签:

【中文标题】flyway:即使 SQL 语句失败也强制迁移【英文标题】:flyway: forcing migrations even if a SQL statement failed 【发布时间】: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 克隆我们的数据库并让开发团队在我准备一组新的迁移时停止他们的开发之外,还有其他想法吗?

【问题讨论】:

【参考方案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 测试

【讨论】:

以上是关于flyway:即使 SQL 语句失败也强制迁移的主要内容,如果未能解决你的问题,请参考以下文章

尝试在 sql-server 上迁移时 Flyway 挂起

使用flyway迁移到Google Cloud SQL,应该复制哪些jar文件?

FlywayDB:迁移失败并显示“执行语句错误”,但手动运行迁移 SQL 代码有效

Flyway 迁移在 MS SQL Server 中成功,但在 H2 数据库中失败

使用 Spring Boot 记录 Flyway sql

如何在 SQL Server 上的 Flyway 中禁用单个迁移的事务