使用git/gerrit进行迭代的数据库迁移



问题:如何处理缓慢提交/gerrit的顺序数据库迁移脚本

设置如下:

  • 数据库表的持续开发是通过添加具有顺序名称(12)的文件来完成的。sql, 13岁。sql, 14。sql等)
  • 在数据库
  • 中设置一个版本号。
  • 一个迁移工具根据文件检查版本,看看是否有未处理的数据库迁移

这种方法的主要问题是,当两个开发人员同时添加迁移脚本时,最后提交的人会得到合并冲突。在subversion中(我们一直使用subversion),这是一个树冲突,提交者通过恢复该文件并使用新文件名添加它作为最后的操作来处理它。由于我们在主干上使用这些东西,他们通常会设法修复文件名作为最后的快速操作。

现在我们正在迁移到git,冲突将在文件中显示为diff,使得分离两个提交的文件(它们可能是不同提交包的一部分,以及其他文件)变得更加棘手。此外,由于我们使用gerrit来进行代码审查,因此在将文件推送到git主存储库和将文件获取到主存储库之间会有延迟,导致这种情况不时出现:

  1. 推送迁移
  2. Gerrit在代码审查后得到冲突
  3. 您可以通过重命名文件来修复冲突,并推送一个新的提交(必须重新审查)
  4. 有人设法在代码审查之前得到一个新的迁移,所以Gerrit再次得到冲突
  5. 您可以通过重命名文件来修复冲突,并推送一个新的提交(必须重新审查)
  6. 从4开始重复,直到你足够幸运,Gerrit成功地提交了迁移。
解决这种情况的最好方法是什么?

我使用liquidbase来管理我的数据库迁移。

它使用XML语法向数据库描述每个"变更集"。虽然这可能是采用的一个障碍,但我发现它可以更容易地将来自不同开发人员的贡献合并到同一个文件中。

<changeSet id="bob-20130115-1" author="bob">
    <createTable tableName="commontable">
       ..
       ..
    </createTable>
</changeSet>
<changeSet id="tom-20130115-1" author="tom">
    <addColumn tableName="commontable">
        <column name="newcolumn" type="varchar(255)"/>
    </addColumn>
</changeSet>

使用liquidbase的第二个优点是它支持回滚。如果发生冲突,我们可以撤销变更集,将我们带回上一个稳定版本,修复迁移文件并执行新的更新。

如果你没有切换工具的奢侈,那么我建议也许采用liquibase的方法,将开发期间的每次迁移视为一个"变更集"。对每个迭代使用单个迁移文件,并在每个开发人员贡献的开始和结束处添加注释。在合并冲突的情况下,不要试图重写SQL,而是重新排序,以便一个开发人员的更改在其他人之前或之后进行。(强迫其他开发人员创建另一个文件的方法是有效的,但我发现在实践中很难实现,当第三个开发人员随后出现并与序列中的下一个数字冲突....)

管理没有回滚功能的集成环境是棘手的....除了每次从头开始重建数据库之外,我不知道任何简单的方法。也许唯一有效的方法是遵循VonC的建议,将数据库更改器的数量保持在最低限度。

指出:

  • 每个开发人员使用自己的数据库是给定的。您正在使用迁移工具,因此应该没有异议。它简化了问题,特别是当您需要删除并重新构建模式时。它还迫使您解决"测试数据"挑战....当我在一个项目上工作时,测试数据位于单个数据库实例....
  • 我最近发现SQL Alchemy迁移具有与liquidbase相同的回滚功能。它迫使您为每次迁移编写前滚和回滚脚本。

我选择Liquibase作为一种溶液。Liquibase的一个属性Mark O'Connor没有很好地指出,Liquibase维护了一个列表在您的方法中最后应用的更改。

因此(只要变更标识符不冲突)分支不是问题所在。Liquibase只是应用所有尚未在XML中按顺序应用的未完成的更改集。作为一项检测冲突的功能,Liquibase还存储了更改集源代码本身的MD5哈希值,因此它也能够检测更改"XY"本身的内容是否被更改。在这种情况下,您必须手动找出出错的地方,并教导您的开发人员同事不要在任何第三方应用更改集之后更改更改集。

如果你不想切换/引入一个新的数据库版本控制工具,如liquibase,我认为你可以很容易地向这个方向扩展你的自定义方法。只需维护一个应用更改列表,只要文件名不匹配,就可以很好地处理分支。

两个开发人员同时添加迁移脚本

他们需要在自己的分支上进行修改,并触发对Gerrit的单独审查。
一个集成商(或两个开发人员中的一个)将负责合并和审查两个开发工作。

或者两者之间的通信需要改进,如果"dev 1"需要在"dev 1"的工作树中首先获得一些补丁(代表"dev 2"的工作),那么"dev 1"就不会在没有与"dev 2"检查的情况下推送任何东西。

最新更新