【问题标题】:Non linear development and version control on function based database基于函数的数据库的非线性开发和版本控制
【发布时间】:2018-02-02 08:59:55
【问题描述】:

我正在开发一个后端高度基于数据库函数的 Web 应用程序,即大部分业务逻辑发生在 Postgres PLV8 函数中。 (无论好坏,我们都被这种结构所束缚。)

目前,我们使用 Flyway 来管理功能代码。如果一切都保持线性,那效果很好。但是,想象一下以下情况:

给定一个这样的函数:

CREATE OR REPLACE FUNCTION public.feed_dog()
  RETURNS jsonb AS
$BODY$
   plv8.execute("SELECT prepare_cat_food()");
   plv8.execute("UPDATE dog SET hunger_status = 'good'");
$BODY$
  LANGUAGE plv8;

假设这个功能今天部署到生产环境中,明天我们开始开发我们的新功能“狗粮健康检查”(对于文件系统上的“正常”代码,我们为此创建了一个 Git 分支。对于数据库: 也许是一个新的数据库?)。 5 天后,新功能分支中的功能可能如下所示:

CREATE OR REPLACE FUNCTION public.feed_dog()
  RETURNS jsonb AS
$BODY$
   plv8.execute("SELECT dog_food_health_check()");
   plv8.execute("UPDATE dog_food_health SET 'status' = 'healthy'");
   plv8.execute("SELECT prepare_cat_food()");
   plv8.execute("UPDATE dog SET hunger_status = 'good'");
$BODY$
  LANGUAGE plv8;

但是,由于缺少重要部分,我们尚未部署。

现在,就在同一天,有人发现我们把狗和猫混为一谈,用prepare_cat_food而不是prepare_dog_food

因此,使用 Flyway 迁移完成了一个 Hotfix,它将完全覆盖整个函数 feed_dog

CREATE OR REPLACE FUNCTION public.feed_dog()
  RETURNS jsonb AS
$BODY$
   plv8.execute("SELECT prepare_dog_food()");
   plv8.execute("UPDATE dog SET hunger_status = 'good'");
$BODY$
  LANGUAGE plv8;

因此,如果我将该迁移应用到“狗粮健康检查”分支,feed_dog 函数中开发的所有新功能都将被 Flyway 迁移覆盖。 相反,我们需要的是一个 Git 风格的合并和冲突解决机制,在这种情况下,它会停在 plv8.execute("SELECT prepare_dog_food()"); 行并需要人工审查,以便最终新功能与错误已修复。

我们如何使用 Flyway 做到这一点?

或者它是否适用于 Liquibase?他们不知何故有一个分支概念,但到目前为止我还不明白它是如何用于非线性开发的。

【问题讨论】:

  • 如果你想要git机制,我会说使用git。 sqitch 提供了一些非线性部署,但它也不会为您解决冲突...
  • @Vao Tsun 我们的 Git 到底怎么样?每次更改某些内容时复制和粘贴每个功能非常烦人。我会说,为此编写脚本也很重要。
  • 好吧。 flyway有版本afaik。所以如果你从不同的 git 分支运行相同的版本,它会说它已经安装了?.. sqitch 也是如此 - 如果你部署了一个名称,它不会重新部署它。所以最简单的方法是使用分支并通过从分支运行 sql 来安装新的 funcyion 定义。 psql -f ddl.sql 或类似的
  • @Vao Tsun 我不明白。运行 psql -f ddl.sql 将与 Flyway 一样:覆盖现有函数,无论它们来自哪个分支等。如果函数定义在途中出现分歧,则运行 psql 的最后一个分支将获胜,并且之前的所有更改都将消失。我需要的是一种自动方法:将每个 DB 函数放入文件系统上的文件中。通过 Git 提交并推送它们。拉动时解决冲突。通过 SQL 将所有函数定义放回数据库。但是,我不知道这样的事情,而且我猜想发展自己需要数周时间。
  • 1.结帐到分支 2. 执行 sql,更改 db 中的定义。 3 一段时间后结帐到其他分支并执行相同操作 - 重写 db 中函数的定义。冲突和合并由 git 在合并分支上完成。并且是真的 - 很可能我只是不明白这个问题 - 抱歉

标签: postgresql version-control liquibase flyway


【解决方案1】:

如果我正确理解您的问题,您需要结合使用两种技术:

(1) 将每个函数保存在一个源代码文件中: 您需要它来利用版本控制系统的冲突解决功能。

(2) 支持 Flyway 中的乱序迁移: 如何实现这一点在此处的一篇优秀文章中进行了描述: http://www.jeremyjarrell.com/using-flyway-db-with-distributed-version-control/

基本上,您需要做的是在每次更改函数后,您必须在包含该函数新版本的相关分支中创建一个 Flyway 迁移脚本。鉴于您的示例,这在实践中将如下所示:

  1. 初始状态:

主干中的feed_dog.sql

CREATE OR REPLACE FUNCTION public.feed_dog()
  RETURNS jsonb AS
$BODY$
   plv8.execute("SELECT prepare_cat_food()");
   plv8.execute("UPDATE dog SET hunger_status = 'good'");
$BODY$
  LANGUAGE plv8;
  1. 创建健康检查分支后

分支中的feed_dog.sql:

CREATE OR REPLACE FUNCTION public.feed_dog()
  RETURNS jsonb AS
$BODY$
   plv8.execute("SELECT dog_food_health_check()");
   plv8.execute("UPDATE dog_food_health SET 'status' = 'healthy'");
   plv8.execute("SELECT prepare_cat_food()");
   plv8.execute("UPDATE dog SET hunger_status = 'good'");
$BODY$
  LANGUAGE plv8;
  1. 在主干中应用修复后:

后备箱中的feed_dog.sql:

CREATE OR REPLACE FUNCTION public.feed_dog()
  RETURNS jsonb AS
$BODY$
   plv8.execute("SELECT prepare_dog_food()");
   plv8.execute("UPDATE dog SET hunger_status = 'good'");
$BODY$
  LANGUAGE plv8;

主干中的V20170830_124459_hotfix_dogfood.sql: 与 feed_dog.sql 内容相同

  1. 将主干的更改合并到功能分支后:

功能分支中的feed_dog.sql:

CREATE OR REPLACE FUNCTION public.feed_dog()
  RETURNS jsonb AS
$BODY$
   plv8.execute("SELECT dog_food_health_check()");
   plv8.execute("UPDATE dog_food_health SET 'status' = 'healthy'");
   plv8.execute("SELECT prepare_dog_food()");   -- Merged here
   plv8.execute("UPDATE dog SET hunger_status = 'good'");
$BODY$
  LANGUAGE plv8;

功能分支中的V20170831_135559_merged.sql: 与 feed_dog.sql 内容相同

feed_dog.sql 是函数 feed_dog() 的源代码文件。 “V”文件是根据上述文章中的建议命名约定的迁移脚本。 重新集成功能分支后,Flyway 将执行 V20170830_124459_hotfix_dogfood.sql 和 V20170831_135559_merged.sql。

【讨论】:

    【解决方案2】:

    Wombat's answer's 理解为基础...

    repeatable migrations 与各自文件中的每个函数一起使用。然后 Flyway 将在每次更改时应用它们。使用版本控制管理每个功能文件,例如R__feed_dog.sql。这样可以避免每次都将更新后的函数复制并粘贴到版本化迁移中。

    以前的经验笔记:

    • 如果函数之间存在依赖关系,则在描述的开头添加一个数字以强制按顺序应用 flyway,例如 R__010_framework.sql, R__200_use_of_framework.sql。这在进入空架构时最重要
    • 打开调试日志,这将在日志中输出可重复迁移的内容,以帮助审计
    • Flyway 版本化迁移之后应用可重复迁移,因此如果您的版本化迁移使用这些函数,则需要小心

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-04
      • 1970-01-01
      相关资源
      最近更新 更多