跟踪数据库架构更改的机制

时间:2008-08-04 21:31:40

标签: php mysql database svn migration

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

许多流行的软件包都包含自动更新脚本,可以检测数据库版本并应用必要的更改。这是否是即使在更大规模(跨多个项目,有时还有多个环境和语言)中实现这一目标的最佳方式?如果是这样,是否有任何现有的代码可以简化流程,或者最好只是推出我们自己的解决方案?有没有人之前实现过类似的东西并将它集成到Subversion后提交钩子中,或者这是一个坏主意?

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

20 个答案:

答案 0 :(得分:55)

在Rails世界中,存在迁移的概念,其中对数据库的更改是在Ruby中进行的,而不是数据库特定的SQL。您的Ruby迁移代码最终会转换为特定于当前数据库的DDL;这使得切换数据库平台非常容易。

对于您对数据库所做的每一项更改,您都要编写一个新的迁移。迁移通常有两种方法:应用更改的“向上”方法和撤消更改的“向下”方法。单个命令使数据库保持最新,还可用于将数据库引入特定版本的模式。在Rails中,迁移保存在项目目录中它们自己的目录中,并像任何其他项目代码一样检入版本控制。

This Oracle guide to Rails migrations很好地涵盖了迁移。

使用其他语言的开发人员已经查看了迁移并已实现了自己的语言特定版本。我知道 Ruckusing ,这是一个以Rails迁移为模型的PHP迁移系统;它可能就是你要找的东西。

答案 1 :(得分:49)

我们使用类似于bcwoord的东西来保持我们的数据库模式在5个不同的安装(生产,登台和一些开发安装)中同步,并在版本控制中备份,并且它运行良好。我会详细说明一下:


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

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

更新脚本的工作方式如下:

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

所有内容都进入源代码控制,每个安装都有一个脚本,可以通过单个脚本执行更新到最新版本(使用正确的数据库密码调用update.php等)。我们SVN通过自动调用数据库更新脚本的脚本更新登台和生产环境,因此代码更新带有必要的数据库更新。

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


设置这个系统只需要几个小时,它在概念上很简单,并且每个人都获得了版本编号方案,并且它具有推动和发展数据库设计的能力,无需进行通信或手动,这是非常宝贵的在所有数据库上执行修改。

当从phpMyAdmin粘贴查询时要小心!这些生成的查询通常包含数据库名称,你绝对不需要它,因为它会破坏你的脚本!如果系统上的数据库未被调用mydb,那么像CREATE TABLE mydbnewtable(...)之类的东西将会失败。我们创建了一个预注释SVN挂钩,它将禁止包含mydb字符串的.sql文件,这是一个明确的信号,表示有人在没有正确检查的情况下从phpMyAdmin复制/粘贴。

答案 2 :(得分:11)

我的团队编写了所有数据库更改脚本,并将这些脚本与应用程序的每个版本一起提交到SVN。这允许数据库的增量更改,而不会丢失任何数据。

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

答案 3 :(得分:9)

如果您仍在寻找解决方案:我们正在推荐一款名为neXtep designer的工具。它是一个数据库开发环境,您可以使用它来控制整个数据库。您在版本控制的存储库上工作,可以跟踪每个更改。

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

然后您有很多选择:您可以使用这些脚本并将其与您的应用程序代码一起放入SVN,以便它可以通过现有机制进行部署。另一种选择是使用neXtep的传递机制:脚本以称为“传递包”(SQL脚本+ XML描述符)的方式导出,安装程序可以理解此包并将其部署到目标服务器,同时确保条件一致性,依赖性检查,注册已安装的版本等

该产品是GPL,基于Eclipse,因此可在Linux,Mac和Windows上运行。它目前还支持Oracle,Mysql和Postgresql(DB2支持即将推出)。看一下维基,在那里您可以找到更多详细信息: http://www.nextep-softwares.com/wiki

答案 4 :(得分:9)

这里的问题确实让开发人员可以轻松地将他们自己的本地更改编写到源代码控制中,以便与团队共享。多年来我一直面临这个问题,并受到Visual Studio for Database专业人员功能的启发。如果您想要一个具有相同功能的开源工具,请尝试以下操作:http://dbsourcetools.codeplex.com/ 玩得开心, - 内森。

答案 5 :(得分:6)

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

答案 6 :(得分:6)

Scott Ambler撰写了一系列关于数据库重构的文章(并共同撰写了一篇book),并认为您应该基本上应用TDD原则和实践来维护您的架构。您为数据库设置了一系列结构和种子数据单元测试。然后,在更改任何内容之前,您可以修改/编写测试以反映该更改。

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

事实证明,开发人员有时也会调整他们的沙箱数据库而忽略更新SVN中的模式文件。然后代码依赖于尚未检入的数据库更改。这种类型的错误可能很难确定,但测试套件会立即启动它。如果您将其内置到更大的持续集成计划中,这将特别好。

答案 7 :(得分:5)

ķ。 Scott Allen在架构版本控制方面有一两篇不错的文章,它使用了其他答案中引用的增量更新脚本/迁移概念;见http://odetocode.com/Blogs/scott/archive/2008/01/31/11710.aspx

答案 8 :(得分:4)

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

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

对于更新,我们在硬编码的软件中添加更新。我们保持硬编码,因为我们不喜欢在问题真正解决之前解决问题,到目前为止,这种事情并不是一个问题。

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

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

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

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

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

此外,我们不支持降级,但它是按设计,如果更新时出现问题,我们会在重新尝试之前恢复以前的版本并修复更新。

答案 9 :(得分:4)

我在Visual Studio中为几个项目使用了以下数据库项目结构,并且它运行良好:

数据库

  

更改脚本

     
    

0.PreDeploy.sql

         

1.SchemaChanges.sql

         

2.DataChanges.sql

         

3.Permissions.sql

  
     

创建脚本

     
    

存储过程

         

功能

         

浏览

  

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

  

1.PreDeploy.sql

     

2.SchemaChanges.sql

     

“创建脚本”文件夹的内容

     

2.DataChanges.sql

     

3.Permissions.sql

每个开发人员通过将代码附加到每个文件的末尾来检查他们对特定错误/功能的更改。主要版本完成并在源代码管理中分支后,将删除Change Scripts文件夹中.sql文件的内容。

答案 10 :(得分:4)

它有点低技术,并且可能有更好的解决方案,但您可以将模式存储在可以运行以创建数据库的SQL脚本中。我认为您可以执行命令来生成此脚本,但遗憾的是我不知道该命令。

然后,将脚本与处理它的代码一起提交到源代码控制中。当您需要更改架构以及代码时,可以检查脚本以及需要更改架构的代码。然后,脚本上的差异将指示架构更改的差异。

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

答案 11 :(得分:4)

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

http://subsonicproject.com/

答案 12 :(得分:3)

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

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

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

就像Joey所说,如果您处于Rails世界,请使用迁移。 :)

答案 13 :(得分:2)

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

答案 14 :(得分:2)

我建议将Ant(跨平台)用于“脚本”方面(因为它实际上可以通过jdbc与任何数据库通信)和Subversion用于源存储库。 在进行更改之前,Ant会让您将数据库“备份”到本地文件。 1.通过Ant将现有的db模式备份到文件 2.通过Ant将版本控制到Subversion存储库 3.通过Ant

向db发送新的sql语句

答案 15 :(得分:2)

答案 16 :(得分:2)

对于我当前的PHP项目,我们使用rails迁移的概念,我们有一个迁移目录,我们在其中保存文件标题“migration_XX.sql”,其中XX是迁移的编号。目前,这些文件是在进行更新时手动创建的,但是可以轻松修改它们的创建。

然后我们有一个名为“Migration_watcher”的脚本,因为我们处于pre-alpha状态,目前在每个页面加载时运行,并检查是否有新的migration_XX.sql文件,其中XX大于当前的迁移版本。如果是这样,它会运行所有migration_XX.sql文件,最大数量是针对数据库的,并且瞧!架构更改是自动化的。

如果你需要恢复系统的能力需要大量的调整,但它很简单,并且迄今为止我们相当小的团队工作得非常好。

答案 17 :(得分:2)

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

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

有关详细信息,请参阅手册中的Database Migration文章。

答案 18 :(得分:2)

恕我直言的迁移确实存在很大的问题:

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

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

答案 19 :(得分:0)

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