跟踪 DB 模式更改的机制

跟踪和/或自动化 DB 模式更改的最佳方法是什么?我们的团队使用 Subversion 进行版本控制,并且我们已经能够以这种方式自动化我们的一些任务(将构建推送到登台服务器,将测试代码部署到生产服务器) ,但是我们仍然在手动进行数据库更新。我希望找到或创建一种解决方案,使我们能够在不同环境的服务器之间高效地工作,同时继续使用 Subversion 作为后端,通过它将代码和 DB 更新推送到各种服务器。

许多流行的软件包包括自动更新脚本,检测数据库版本和应用必要的变化。这是在更大范围内(跨多个项目,有时是跨多个环境和语言)实现此目的的最佳方法吗?如果是这样的话,是否有现有的代码可以简化流程,或者最好只使用我们自己的解决方案?之前有人实现过类似的东西并将其集成到 Subversion 后提交钩子中吗? 或者这是个坏主意?

虽然支持多个平台的解决方案更可取,但我们绝对需要支持 Linux/Apache/MySQL/PHP 堆栈,因为我们的大部分工作都是在该平台上进行的。

43677 次浏览

这是一种低技术,可能有一个更好的解决方案,但您可以只存储您的模式在一个 SQL 脚本,可以运行创建数据库。我认为您可以执行一个命令来生成这个脚本,但不幸的是,我不知道这个命令。

然后,将脚本连同在其上运行的代码一起提交到源代码管理中。当需要随代码一起更改架构时,可以将脚本与需要更改架构的代码一起签入。然后,脚本上的差异将表明模式更改上的差异。

使用这个脚本,您可以将它与 DBUnit 或某种构建脚本集成,因此它似乎可以适合您已经自动化的流程。

在 Rails 世界中,有迁移的概念,在这些脚本中,对数据库的更改是用 Ruby 完成的,而不是特定于数据库的 SQL。Ruby 迁移代码最终被转换为当前数据库特有的 DDL; 这使得切换数据库平台非常容易。

对于对数据库进行的每次更改,都要编写一个新的迁移。迁移通常有两个方法: 一个是应用更改的“ up”方法,另一个是撤消更改的“ down”方法。一个简单的命令就可以使数据库更新,还可以用来将数据库转换为模式的特定版本。在 Rails 中,迁移保存在项目目录中它们自己的目录中,并像其他任何项目代码一样签入版本控制。

这个 Oracle 的 Rails 迁移指南 很好地涵盖了迁移。

使用其他语言的开发人员已经研究了迁移,并实现了自己的特定语言版本。我知道 翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳,这是一个仿照 Rails 迁移建模的 PHP 迁移系统; 它可能就是您正在寻找的。

如果您正在使用 C # ,请看一下 Subsonic,一个非常有用的 ORM 工具,但它也生成 sql 脚本来重新创建您的方案和或数据。然后可以将这些脚本放入源代码管理中。

Http://subsonicproject.com/

我创建以构建版本命名的文件夹,并在其中放入升级和降级脚本。例如,您可以有以下文件夹: 1.0.0、1.0.1和1.0.2。每个版本都包含允许您在不同版本之间升级或降级数据库的脚本。

如果客户或客户因版本1.0.1的问题打电话给您,而您使用的是1.0.2,那么将数据库恢复到他的版本将不成问题。

在数据库中,创建一个名为“ schema”的表,将其放入当前版本的数据库中。然后编写一个可以升级或降级您的数据库的程序是很容易的。

就像 Joey 说的,如果你在一个 Rails 的世界里,使用迁移。 :)

我的团队编写出所有数据库更改的脚本,并将这些脚本提交给 SVN,以及应用程序的每个版本。这允许对数据库进行增量更改,而不会丢失任何数据。

要从一个版本到下一个版本,您只需要运行一组变更脚本,您的数据库是最新的,并且您仍然拥有所有的数据。这可能不是最简单的方法,但绝对是有效的。

将架构转储到文件中并将其添加到源代码管理中。然后一个简单的差异将显示您改变了什么。

我们使用一个非常简单但是有效的解决方案。

对于新的安装,我们在存储库中有一个 metadata.sql 文件,其中包含所有的 DB 模式,然后在构建过程中,我们使用该文件来生成数据库。

对于更新,我们在硬编码的软件中添加更新。我们保持它的硬编码,因为我们不喜欢解决问题之前,它真的是一个问题,这种事情没有证明是一个问题,迄今为止。

所以在我们的软件中,我们有这样的东西:

RegisterUpgrade(1, 'ALTER TABLE XX ADD XY CHAR(1) NOT NULL;');

这段代码将检查数据库是否在版本1中(存储在自动创建的表中) ,如果数据库过时,则执行命令。

为了更新存储库中的 metadata.sql,我们在本地运行此更新,然后提取完整的数据库元数据。

唯一经常发生的事情,就是忘记提交 metadata.sql,但这并不是一个大问题,因为它很容易在构建过程中测试,而且唯一可能发生的事情就是用过时的数据库创建一个新的安装,并在第一次使用时升级它。

另外,我们不支持降级,但它是根据设计,如果有什么打破了更新,我们恢复了以前的版本和修复更新之前,再次尝试。

我在 VisualStudio 中使用过以下数据库项目结构,并且运行得非常好:

数据库

更改脚本

0. PreDeploy.sql

1. SchemaChanges.sql

2. DataChanges.sql

3. 许可

创建脚本

Sprocs

职能

观点

然后,我们的构建系统按以下顺序执行脚本,从一个版本更新到下一个版本:

1. PreDeploy.sql

2. SchemaChanges.sql

创建脚本文件夹的内容

2. DataChanges.sql

3. 许可

每个开发人员通过将代码附加到每个文件的末尾来检查对特定 bug/特性的更改。一旦主版本完成并在源代码管理中分支,则。删除 ChangeScripts 文件夹中的 sql 文件。

我们使用类似 bcword 的东西来保持数据库模式在5个不同的安装(生产、登台和一些开发安装)之间的同步,并在版本控制中进行备份,它工作得非常好。我会详细说明一下:


为了同步数据库结构,我们有一个脚本 update.php 和许多编号为1.sql、2.sql、3.sql 等的文件。该脚本使用一个额外的表来存储数据库的当前版本号。N.sql 文件是手工制作的,从数据库的版本(N-1)到版本 N。

它们可以用来添加表、添加列、将数据从旧的列格式迁移到新的列格式,然后删除列、插入“主”数据行,如用户类型等。基本上,它可以做任何事情,使用适当的数据迁移脚本,您将永远不会丢失数据。

更新脚本的工作原理如下:

  • 连接到数据库。
  • 备份当前数据库(因为 威尔出错)[ mysqldump ]。
  • 如果不存在簿记表(称为 _ meta) ,则创建它。
  • 从 _ meta 表中读取当前版本。如果找不到,假设为0。
  • 对于所有编号高于 VERSION 的.sql 文件,按顺序执行它们
  • 如果其中一个文件产生错误: 回滚到备份
  • 否则,将簿记表中的版本更新为执行的最高.sql 文件。

所有东西都进入源代码控制,每个安装都有一个脚本,通过执行一个脚本(使用适当的数据库密码调用 update.php 等)来更新到最新版本。我们 SVN 通过一个自动调用数据库更新脚本的脚本来更新临时和生产环境,因此代码更新包含必要的数据库更新。

我们还可以使用相同的脚本从头开始重新创建整个数据库; 我们只需删除并重新创建数据库,然后运行将完全重新填充数据库的脚本。我们还可以使用该脚本填充一个空数据库以进行自动化测试。


建立这个系统只花了几个小时,它的概念很简单,每个人都有版本编号,而且它在数据库设计的进步和发展方面非常有价值,无需在所有数据库上进行交流或手动执行修改。

但是在粘贴来自 phpMyAdmin 的查询时要小心!那些生成的查询通常包含数据库名称,您肯定不想要这个名称,因为它会破坏您的脚本!如果系统上的数据库不称为 mydb,那么像 CREATE TABLE mydb.newtable(...)这样的操作就会失败。我们创建了一个注释前 SVN 挂钩,它将不允许。Sql 文件包含 mydb字符串,这是一个确定的信号,表明有人未经适当检查就从 phpMyAdmin 复制/粘贴。

对于我目前的 PHP 项目,我们使用了 Rails 迁移的思想,并且我们有一个迁移目录,其中保存了标题为“ mobile _ XX.sql”的文件,其中 XX 是迁移的数量。目前,这些文件是在进行更新时手工创建的,但是它们的创建可以很容易地进行修改。

然后,我们有一个名为“ Immigration _ watcher”的脚本,正如我们在 pre-alpha 中一样,它目前在每个页面加载时运行,并检查是否有一个新的迁移 _ XX.sql 文件,其中 XX 比当前的迁移版本大。如果是这样的话,它将对数据库运行迁移 _ XX.sql 文件到最大数量,瞧!模式更改是自动的。

如果您需要恢复系统的能力将需要大量的调整,但它很简单,并已经为我们相当小的团队工作到目前为止。

Scott Ambler 撰写了一系列关于数据库重构的文章(并与人合著了 ) ,其中的想法是您应该基本上应用 TDD 原则和实践来维护您的模式。您为数据库设置了一系列结构和种子数据单元测试。然后,在更改任何内容之前,修改/编写测试以反映该更改。

我们这么做已经有一段时间了,而且似乎奏效了。我们编写了代码来在单元测试套件中生成基本的列名和数据类型检查。我们可以随时重新运行这些测试,以验证 SVN 签出中的数据库是否与应用程序实际运行的活动数据库匹配。

事实证明,开发人员有时也会调整他们的沙箱数据库,而忽略更新 SVN 中的模式文件。然后,代码依赖于尚未签入的 db 更改。这种类型的 bug 很难确定,但是测试套件会马上发现它。如果您将其内置到更大的持续集成计划中,那么这种方法尤其好。

Scott Allen 有一两篇关于模式版本控制的文章,使用了这里其他答案中引用的增量更新脚本/迁移概念; 参见 http://odetocode.com/Blogs/scott/archive/2008/01/31/11710.aspx

我建议在“脚本”方面使用 Ant (跨平台)(因为它实际上可以通过 jdbc 与任何 db 进行通信) ,在源代码存储库中使用 Subversion。 Ant 允许您在进行更改之前将数据库“备份”到本地文件。

  1. 通过 Ant 将现有的 db 模式备份到文件
  2. 通过 Ant 将版本控制传递到 Subversion 存储库
  3. 通过 Ant 向 db 发送新的 sql 语句

这里的问题是,开发人员可以很容易地将自己的本地更改编写到源代码控制中,以便与团队共享。我已经面对这个问题很多年了,并且受到 VisualStudioforDatabase 专业人员的功能的启发。如果你想要一个具有相同功能的开源工具,可以试试这个 http://dbsourcetools.codeplex.com/ 玩得开心, 内森。

有一个比较数据库架构的命令行 Mysql-diff工具,其中架构可以是磁盘上的实时数据库或 SQL 脚本。它适用于最具模式迁移的任务。

如果您仍然在寻找解决方案: 我们提出了一个名为 neXtep 设计器的工具。它是一个数据库开发环境,您可以使用它将整个数据库置于版本控制之下。您使用的是一个版本控制存储库,在该存储库中可以跟踪每个更改。

当您需要发布更新时,您可以提交组件,产品将自动生成来自以前版本的 SQL 升级脚本。当然,您可以从任意2个版本生成这个 SQL。

然后您有很多选择: 您可以将这些脚本和应用程序代码一起放在您的 SVN 中,这样就可以通过现有的机制部署它们。另一种选择是使用 neXtep 的传递机制: 脚本被导出为一个“传递包”(SQL 脚本 + XML 描述符) ,安装程序可以理解这个包并将其部署到目标服务器,同时确保结构一致性、依赖性检查、注册安装版本等。

该产品采用 GPL 协议,基于 Eclipse,因此可以在 Linux、 Mac 和 Windows 上运行。目前它还支持 Oracle、 MySQL 和 PostgreSQL (DB2支持即将到来)。看看维基百科,你会发现更多的详细信息: Http://www.nextep-softwares.com/wiki

Toad for MySQL 有一个名为模式比较的函数,它允许您同步2个数据库。这是迄今为止我使用过的最好的工具。

恕我直言,移民确实有一个巨大的问题:

从一个版本升级到另一个版本可以很好地工作,但是如果您有数百个表并且有很长的更改历史(就像我们所做的那样) ,那么重新安装给定的版本可能会花费很长时间。

从基线到当前版本(对于数百个客户数据库)运行 delta 的整个历史可能需要很长时间。

我喜欢 处理数据库迁移的方式。迁移基本上是一个实现 CDbMigration的 PHP 脚本。CDbMigration定义了一个包含迁移逻辑的 up方法。还可以实现一个 down方法来支持迁移的反转。或者,可以使用 safeUpsafeDown来确保在事务上下文中完成迁移。

Yii 的命令行工具 yiic包含创建和执行迁移的支持。可以应用或逆转迁移,一个一个或一批地进行。创建迁移会导致实现 CDbMigration的 PHP 类的代码,该类基于时间戳和用户指定的迁移名称进行唯一命名。以前应用于数据库的所有迁移都存储在迁移表中。

有关详细信息,请参阅手册中的 数据库迁移文章。