8

描述起来有点复杂,但我会尽力而为。基本上我们使用的是 Git 工作流程,这意味着我们有以下分支:

  • 生产,这是现场分支。一切都是生产在实时网络环境中运行。
  • 集成,其中集成了所有新功能。这个分支每周都会合并到生产环境中。
  • 一个或多个功能分支,开发人员或开发团队在其中开发新功能。完成此操作后,开发人员将他们的功能分支合并到集成中。

所以,这里没有什么复杂的。但是,由于我们的应用程序是针对 MySQL 数据库运行的 Web 应用程序,因此新功能通常需要更改数据库方案。为了自动化这个,我们使用 dbdeploy,它允许我们创建改变脚本,给定一个数字。例如 00001.sql、00002.sql 等。在合并到集成分支后,dbdeploy 将检查哪些更改脚本的编号高于该特定数据库上最新执行的脚本,并将执行这些脚本。

现在假设如下。- 集成在 00200.sql 之前有更改脚本。所有这些都在集成数据库上执行。- 开发人员 John 有一个功能分支 featureX,它是在集成仍将 00199.sql 作为最高更改脚本时创建的。

由于一些必需的数据库架构更改,John 创建了 00200.sql。

现在,在某个时候,John 会将他的修改合并回集成分支。John 会遇到合并冲突,并且会看到他的 00200.sql 已经存在于集成中。这意味着他需要打开有冲突的文件,提取他的内容,将该文件重置回“我的”(集成中的原始状态)并将他自己的内容放入一个新文件中。

现在,由于我们与十名开发人员合作,我们每天都会遇到这种情况。虽然我们确实了解这背后的原因,但有时非常麻烦。John 重命名他的脚本,对集成进行合并提交,将更改推送到上游,只是看到其他人已经创建了 00201.sql,要求 John 再次执行这些过程。

肯定会有更多的团队使用 Git 工作流程并使用数据库更改管理工具来自动化数据库架构更改吗?

所以,简而言之,我的问题是:

  • 当在不同的功能分支上工作时,如何自动化数据库模式更改,这些分支在同一数据库的不同实例上运行?
  • 如何始终防止合并冲突,同时仍然可以选择在执行的更改脚本中具有固定顺序?例如,00199.sql 必须在 00200.sql 之前执行,因为 00200.sql 可能取决于 00199.sql 中所做的某些事情。

当然,任何其他提示都是最受欢迎的。

4

5 回答 5

4

Rails 曾经这样做,正是您描述的问题。他们更改为以下方案:文件(rails 将它们称为迁移)标有文件创建时间的 utc 时间戳,例如

20140723069701_add_foo_to_bar

(名称的第二部分不影响排序)。

Rails 记录所有已运行的迁移的时间戳。当您要求它运行挂起的迁移时,它会选择时间戳不在已运行迁移列表中的所有迁移文件,并按数字顺序运行它们。

除非两个人在完全相同的时间点创建一个,否则您将不再遇到合并冲突。

文件仍然按照您编写它们的顺序执行,但可能与其他人的工作交错。从理论上讲,您仍然可能会遇到问题 - 例如,开发人员决定重命名一个表,而我也决定添加一列。这比两个开发人员都对数据库进行任何更改要少得多,即使不考虑架构更改,您也会遇到问题大概我刚刚编写了查询不再存在的表的代码 - 在某些时候,从事相关工作的开发人员会有互相交谈!

于 2014-07-23T06:18:38.373 回答
2

几点建议:

1 - 看看 Liquibase,每个版本都有一个引用需要发生的更改的文件,然后可以使用有意义的字符串而不是数字来命名更改文件。

2 - 有一个获取下一个可用号码的中心位置,然后人们使用最新的号码。

我过去使用过 Liquibase,非常成功,我们没有遇到您描述的问题。

于 2014-07-23T18:33:28.323 回答
1

正如 Frederick Cheung建议的那样,使用时间戳而不是序列号。按日期戳的顺序应用模式更改应该可以工作,因为模式更改只能依赖于先前日期的更改。

此外,在更改脚本的名称中包含开发人员的名称。这将 100% 防止合并冲突。

您的合并挂钩应该只查找新添加的更改脚本(存在于合并分支中但不在上游分支中)并按时间戳顺序执行它们。

于 2014-07-26T12:53:05.140 回答
0

过去,我使用两种不同的方法来解决您的问题。

第一种是使用可以处理模式更新的ORM 。

另一种方法是创建一个脚本,以增量方式构建数据库模式。这样,如果开发人员需要在表中增加一行,则应在创建表后添加相应的 sql 语句。同样,如果他需要一个新表,他应该为此添加 sql 语句。那么合并就变成了确保事情以正确的顺序发生的问题。这基本上是 ORM 中的数据库更新过程所做的。这样的脚本需要非常防御性地编码,并且每个语句都应检查其特权是否存在。

于 2014-07-22T12:04:36.430 回答
0

对于dbvc 命令行工具,我使用git log来确定更新脚本的顺序。

git log -c --no-merges --pretty="format:" --name-status -p dev/db/updates/ | \
  grep '^A' | awk '{print $2}' | tac

在这种情况下,提交的顺序将决定更新运行的顺序。这很可能是您想要的。

  • 如果您运行git merge b,则将首先运行来自 master 的更新,然后再运行来自 B 的更新。
  • 如果您运行git rebase b,则来自 B 的更新将首先运行,然后是来自 master 的更新。
于 2014-08-02T04:02:35.153 回答