MySQL架构源代码控制

时间:2011-06-01 15:28:39

标签: mysql svn version-control database-schema

在我的公司,我们有几个开发人员都在内部处理项目,每个项目都有自己的虚拟机设置。我们使用SVN来处理源代码,但偶尔会遇到需要更改数据库(MySQL)架构的问题,并且必须将其传播给所有其他开发人员。目前,我们有一个手动编写的日志文件,其中列出了您更改的内容以及执行更改所需的SQL。

我希望有更好的解决方案 - 最好是与SVN相关的解决方案,例如如果更新到版本893,则系统知道这需要数据库修订版183并自动更新本地模式。我们不关心正在同步的数据,只关注模式。

当然,一个解决方案是让所有开发人员在一个中央数据库上运行;然而,这样做的缺点是架构更改可能会破坏其他人的构建,直到他们执行svn为止。

4 个答案:

答案 0 :(得分:2)

一个选项是YAML / JSON中的数据字典。有一篇很好的文章here

答案 1 :(得分:2)

我会考虑查看MyBatis Schema Migration tools之类的内容。这不完全是你所描述的,但我认为它以优雅的方式解决了你的问题,并且可以在不拉入核心MyBatis的情况下使用。

就滚动自己而言,我一直在做的是拥有一个从头开始创建模式的基本模式文件,以及一个将所有模式更改附加为增量的增量文件,由版本号分隔(您可以尝试使用SVN号码,但我总是发现手动增量更容易)。然后有一个schema_version表,其中包含实时数据库中的信息,规范模式文件将包含该信息,并具有一个脚本,该脚本将运行delta脚本中现有数据库版本之后的所有更改。

所以你有一个类似的架构:

-- Version: 1
CREATE TABLE user (
id bigint,
name varchar(20))

您可以使用该工具管理架构版本表,并查看以下内容:

> SELECT * FROM schema_version;
1,2011-05-05

然后你有几个人添加到架构并有一个看起来像这样的增量文件:

-- Version: 2
ALTER TABLE user ADD email varchar(20);
-- Version: 3
ALTER TABLE user ADD phone varchar(20);

使用以下命令检入相应的新架构:

-- Version: 3
CREATE TABLE user (
id bigint,
name varchar(20),
email charchar(20),
phone varchar(20))

当您针对具有初始架构(版本1)的数据库运行增量脚本时,它将从schema_version表中读取值,并将大于该值的所有增量应用于架构。当你开始处理分支时,这会变得更加棘手,但作为一个简单的起点。

答案 2 :(得分:2)

我之前或目前使用的方法有几种:

顺序版本号

大多数使用此方法的程序都有一个单独的程序,它从数据库中获取版本号,然后执行与高于该数字的数据库版本相关的任何语句,最后更新数据库中的版本号。

因此,如果版本为37并且升级应用程序中存在与版本1到38相关联的语句,则它将跳过1到37并执行语句以将数据库带到版本38。

我见过的实现也允许每个版本的降级语句撤消升级所做的事情,这样就可以将数据库从版本38恢复到版本37。

在我的情况下,我们在应用程序本身中进行了此数据库升级,并且没有降级。因此,更改是源代码控制的,因为它们是应用程序的一部分。

定向非循环图

在最近的一个项目中,我想出了一个不同的方法。我使用作为有向非循环图的节点的类来封装语句,以针对每个特定功能/ bugfix /等对数据库进行特定升级。每个节点都有一个属性来声明其唯一名称以及它所依赖的任何节点的名称。这些属性还用于搜索所有升级节点的程序集。

默认根节点是作为没有依赖关系的任何节点的依赖节点,此节点包含用于创建migrationregister表的语句,该表列出了已应用的节点的名称。在将所有节点排序为顺序列表之后,它们将依次执行,跳过已经应用的节点。

这些都包含在与主应用程序不同的应用程序中,并且它们在同一个存储库中受源代码控制,因此当开发人员完成某个功能的工作并且数据库更改与之关联时,它们将一起提交到同样的变化。如果您提取功能的更改,则还会提取数据库更改。此外,主应用程序只需要一个预期节点名称列表。任何额外的或遗漏的,它知道数据库不匹配。

我之所以选择这种方法,是因为该项目通常由多个开发人员进行并行开发,每个开发人员在开发过程中有时会有一件事(分支开发,有时非常分支)。杂耍数据库版本号非常痛苦。如果每个人都从版本37开始并且“Alice”开始使用版本38并因此它将更改她的数据库,并且“Bob”也开始工作,必须更改数据库并且还使用版本38,有人将需要最终更改。所以让我们说鲍勃完成并推送到服务器。现在Alice,当她提取Bob的变更集时,必须将语句的版本更改为39,并将她的数据库版本设置回37,以便Bob的更改将被执行,但随后她再次执行

但是,当Alice推出Bob的变更集时发生的所有事情就是只有一个新的迁移节点和要检查的节点名列表中的另一行,事情才有效。

我们使用Mercurial(分布式)而不是SVN(客户端 - 服务器),因此这种方法对我们来说非常有效。

答案 3 :(得分:1)

一个简单的解决方案是在SVN(或任何库)中保留完整的模式。也就是说,每次更改模式时,运行MySQL“desc”以转储所有表的描述,用此覆盖最后一个这样的模式转储,然后提交。然后,如果你运行版本差异,它应该告诉你改变了什么。当然,您需要按字母顺序(或某些可预测的顺序)保留所有表格。

对于不同的方法:几年前,我参与了一个桌面应用程序项目,我们定期发送可能有架构更改的新版本,我们希望在没有用户干预的情况下处理这些问题。因此该程序描述了它所期望的模式。在启动时,它执行了一些元数据调用来检查它实际拥有的数据库模式,并将它们与预期进行比较。如果然后自动更新架构以匹配其预期。通常当我们添加一个新列时,我们可以简单地让它从null或空白开始,所以一旦我们让第一个版本工作,这就需要很少的编码工作。当填充新字段需要一些实际操作时,我们必须编写自定义代码,但这种情况相对较少。