MySQL架构源代码控制

4
在我们公司,有几个开发人员在内部项目中工作,每个人都有自己的虚拟机设置。我们使用 SVN 处理源代码,但偶尔会遇到需要更改数据库 (MySQL) 模式的问题,这必须传播到所有其他开发人员。目前我们有一个手动编写的日志文件,列出了您更改的内容以及执行更改所需的 SQL。
我希望可能有更好的解决方案 - 理想情况下与 SVN 相关联,例如,如果您更新到修订版 893,系统知道这需要数据库修订版 183 并自动更新本地模式。我们不关心数据被同步,只关心模式。
当然,一种解决方案是让所有开发人员共用一个中央数据库;然而,这具有缺点,即模式更改可能会破坏其他人的构建,直到他们进行 svn up。
4个回答

2
我建议您考虑使用类似于MyBatis模式迁移工具的东西,链接在此:MyBatis Schema Migration tools。虽然它不完全符合您的要求,但我认为它以优雅的方式解决了您的问题,并且可以在不引入核心MyBatis的情况下使用。
如果您想自己开发,我一直采用的方法是有一个基本的模式文件,它可以从头开始创建模式,还有一个增量文件,它将所有模式更改作为增量附加,通过版本号进行分隔(您可以尝试使用SVN号码,但我总是觉得手动递增更容易)。接着,有一个schema_version表,其中包含了当前数据库的信息。规范的模式文件将包含这些信息,并有一个脚本,将运行来自delta脚本的现有DB版本之后的所有更改。
-- 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

一种选择是使用YAML/JSON格式的数据字典。这里有一篇不错的文章(链接)


非常好的表示预期模式的方式。如果我在做这件事,我会简单地将项目设置为将文件嵌入资源中。 - Joel B Fant

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

连续版本号

大多数使用此方法的人都有一个单独的程序,从数据库中获取版本号,然后执行与高于该数字的数据库版本相关联的任何语句,最后更新数据库中的版本号。所以如果版本是37,而升级应用程序中与版本1到38相关联的语句,则会跳过1到37并执行语句,将数据库升级到版本38。
我见过的实现还允许为每个版本提供降级语句,以撤消升级所做的更改,这样可以将数据库从版本38降回版本37。
在我的情况下,我们在应用程序本身中进行了数据库升级,并没有降级。因此,这些更改因为它们是应用程序的一部分,所以被源代码控制。

有向无环图

在最近的一个项目中,我想出了一种不同的方法。我使用类作为有向无环图的节点,封装了针对每个特定功能/错误修复等要升级到数据库的语句。每个节点都有一个属性来声明其唯一名称和它依赖的任何节点的名称。这些属性也用于搜索程序集中的所有升级节点。
对于没有依赖关系的节点,给出一个默认的根节点作为依赖节点,并且该节点包含创建migrationregister表的语句,该表列出已经应用的节点的名称。将所有节点排序成一个连续列表后,依次执行它们,跳过已经应用的节点。
这一切都包含在与主应用程序分离的单独应用程序中,并且它们在同一代码库中进行源代码控制,因此当开发人员完成特定功能和与之相关的数据库更改时,它们会一起提交到同一变更集中。如果你拉取了该功能的更改,则也会拉取数据库更改。此外,主应用程序只需要一个预期的节点名称列表。如果有额外或缺少的节点,则它知道数据库不匹配。
我选择这种方法是因为该项目通常由多个开发人员并行开发,每个开发人员有时会有多个正在开发的事情(分支式开发,有时非常复杂)。管理数据库版本号非常麻烦。如果每个人都从版本37开始,而“Alice”开始做某些事情并使用版本38,以便更改她的数据库,而“Bob”也开始做必须更改数据库的工作,还使用版本38,那么最终有人需要更改。因此,假设Bob完成并推送到服务器。现在Alice在拉取Bob的变更集时,必须将语句的版本更改为39,并将其数据库版本设置回37,以便执行Bob的更改,但然后她的语句再次执行。
但是,当Alice拉取Bob的更改集时,只有一个新的迁移节点和另一行要检查的节点名称列表,事情就变得简单了。
我们使用分布式版本控制系统Mercurial,而不是客户端-服务器版本控制系统SVN,这就是为什么这种方法对我们来说非常有效的原因之一。

1

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

另一种方法:多年前,我曾参与过一个桌面应用程序项目,我们定期发送可能具有模式更改的新版本,并希望处理这些更改而无需用户干预。因此,程序具有所期望模式的描述。在启动时,它进行了一些元数据调用,以检查实际拥有的数据库的模式,并将其与所期望的模式进行比较。然后自动更新模式以匹配所期望的模式。通常,当我们添加新列时,我们可以让它开始为空或空白,因此一旦我们使第一个版本工作起来,这几乎不需要编码工作。当需要进行一些实际操作以填充新字段时,我们必须编写自定义代码,但这相对较少。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接