跟踪数据库模式更改的机制

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

许多流行的软件包包括检测数据库版本并应用必要更改的自动更新脚本。这是甚至在更大规模(跨越多个项目,有时还有多种环境和语言)下做到这一点的最佳方式吗?如果是这样,是否有任何现有代码可以简化流程,或者最好只是推出我们自己的解决方案?有没有人实现过类似的东西,并将其集成到Subversion post-commit挂钩中,或者这是一个坏主意?

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

0
额外 编辑
意见: 9

19 答案

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

然后,将脚本与代码一起提交到源代码控制中。当您需要随代码一起更改模式时,可以将脚本与需要更改的模式的代码一起签入。然后,脚本上的差异将指示模式更改的差异。

有了这个脚本,你可以将它与DBUnit或某种构建脚本集成在一起,所以它看起来可以适应已经自动化的流程。

0
额外
是的,这正是我们现在所拥有的。不幸的是,这并没有给我们一个简单的方法来修改现有的数据库 - 由mysqldump生成的SQL脚本假定您是从头开始创建表(或者覆盖表存在的表)。我们需要更高科技的东西,因为它需要将一系列ALTER TABLE语句应用于数据库,为了正确地做到这一点,需要知道数据库的当前状态。
额外 作者 pix0r,

如果您使用C#,请查看Subsonic,一个非常有用的ORM工具,但也会生成sql脚本来重新创建您的方案和\或数据。这些脚本可以放入源代码控制。

http://subsonicproject.com/

0
额外
对我看起来很好吗?
额外 作者 Dan,
似乎是这个时候的一个死链接。
额外 作者 Mark Schultheiss,
只是喜欢亚音速!
额外 作者 TheVillageIdiot,

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

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

0
额外
你如何编写所有的改变?
额外 作者 Smith,

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

0
额外
差异将显示一列消失,而另一列出现(除非它们具有相同的名称),并且大部分时间足够了。当然,对每个模式更改进行脚本编写都是一个好方法:例如,在Drupal中,这是通过特殊的钩子来处理的。
额外 作者 deadprogrammer,
转储必须在SQL中,就像mysqldump一样,Oracle的转储是二进制的。
额外 作者 Osama Al-Maadeed,
模式差异还有一个更基本的问题。你如何区分列删除+从列重命名添加。答案很简单:你不能。这就是为什么您需要记录实际模式更改操作的原因。
额外 作者 psp,

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

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

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

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

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

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

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

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

此外,我们不支持降级,但是如果在更新中发生故障,我们会恢复以前的版本并在重新尝试之前修复更新。

0
额外

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

如果客户或客户在1.0.1版本中遇到问题并且正在使用1.0.2,则将数据库恢复到其版本不会成为问题。

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

就像Joey说的,如果你在Rails世界,使用Migrations。 :)

0
额外

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

0
额外

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

从一个版本升级到另一个版本可以正常工作,但如果您有数百个表格和长期的更改历史记录(如我们所做的那样),则可能需要永久安装一个给定的版本。

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

0
额外

K. Scott Allen在模式版本控制方面有一篇不错的文章,其中使用了其他答案中引用的增量更新脚本/迁移概念;请参阅 http://odetocode.com/Blogs/scott/archive/ 2008/03/31 / 11710.aspx

0
额外

我们使用类似于bcwoord的东西来保持我们的数据库架构跨5个不同的安装(生产,临时和一些开发安装)同步,并在版本控制中进行备份,并且工作得很好。我会详细说明一下:


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

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

更新脚本的工作原理是这样的:

  • Connect to the database.
  • Make a backup of the current database (because stuff will go wrong) [mysqldump].
  • Create bookkeeping table (called _meta) if it doesn't exist.
  • Read current VERSION from _meta table. Assume 0 if not found.
  • For all .sql files numbered higher than VERSION, execute them in order
  • If one of the files produced an error: roll back to the backup
  • Otherwise, update the version in the bookkeeping table to the highest .sql file executed.

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

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


建立这个系统只需要几个小时,它在概念上很简单,每个人都可以获得版本编号方案,并且它具有向前发展和发展数据库设计的能力,而无需通信或手动执行修改在所有数据库上。

Beware when pasting queries from phpMyAdmin though! Those generated queries usually include the database name, which you definitely don't want since it will break your scripts! Something like CREATE TABLE mydb.newtable(...) will fail if the database on the system is not called mydb. We created a pre-comment SVN hook that will disallow .sql files containing the mydb string, which is a sure sign that someone copy/pasted from phpMyAdmin without proper checking.

0
额外
你是如何处理碰撞的?多个开发人员更改数据库中的相同元素,例如存储过程?如果你在同一个分支上工作,或者你有两条开发线(两个分支)
额外 作者 Asaf Mesika,
碰撞是非常罕见的;唯一发生的事情是,两个人会尝试创建相同的N.sql文件。当然,第一个获胜,第二个被迫重新命名为下一个最高号码,然后重试。不过,我们没有在分支上进行数据库版本控制。
额外 作者 rix0rrr,
0
额外

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

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

ruby on Rails migrations">This Oracle guide to Rails migrations covers migrations quite well.

使用其他语言的开发人员都看着迁移,并实施自己的特定语言版本。我知道的 Ruckusing 下,一个PHP迁移系统的即后Rails的迁移建模;这可能是你在找什么。

0
额外
它现在位于github上: github.com/ruckus/ruckusing-migrations
额外 作者 xXx,
Ruckusing FTW - 我们将它改编成我们的数据库系统,并且非常满意。
额外 作者 Piskvor,
感谢您提及Ruckusing
额外 作者 andho,

我在Visual Studio中为几个项目使用了以下数据库项目结构,并且它工作得很好:

数据库

更改脚本

     
    

0.PreDeploy.sql

         

1.SchemaChanges.sql

         

2.DataChanges.sql

         

3.Permissions.sql

  
     

创建脚本

     
    

存储过程

         

功能

         

浏览

  

Our build system then updates the 数据库 from one version to the next by executing the scripts in the following order:

1.PreDeploy.sql

     

2.SchemaChanges.sql

     

创建脚本文件夹的内容

     

2.DataChanges.sql

     

3.Permissions.sql

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

0
额外

对于我当前的PHP项目,我们使用rails迁移的想法,并且我们有一个migrations目录,其中我们保留文件标题“migration_XX.sql”,其中XX是迁移的编号。目前这些文件是在更新时手动创建的,但是它们的创建可以很容易地修改。

然后,我们有一个名为“Migration_watcher”的脚本,正如我们处于pre-alpha时一样,当前每个页面加载都运行该脚本,并检查是否有新的migration_XX.sql文件,其中XX大于当前的迁移版本。如果是这样,它会将所有migration_XX.sql文件运行到对数据库最大的数字,并且瞧!模式更改是自动的。

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

0
额外

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

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

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

0
额外

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

0
额外

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

0
额外

如果您仍然在寻找解决方案:我们正在提议一种名为neXtep designer的工具。它是一个数据库开发环境,您可以使用该环境将整个数据库置于版本控制之下。你在一个版本控制的存储库上工作,每个变更都可以被跟踪。

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

然后你有很多选择:你可以把这些脚本和你的应用程序代码放到你的SVN中,这样它就可以被你现有的机制部署了。另一个选择是使用neXtep的交付机制:脚本被导出到一个称为“交付包”(SQL脚本+ XML描述符)的东西中,安装程序可以理解此包并将其部署到目标服务器,同时确保一致性,依赖性检查,注册安装的版本等。

The product is GPL and is based on Eclipse so it runs on Linux, Mac and windows. It also support Oracle, Mysql and Postgresql at the moment (DB2 support is on the way). Have a look at the wiki where you will find more detailed information : http://www.nextep-softwares.com/wiki

0
额外
看起来很有趣。它是否也有命令行界面,还是有计划的?
额外 作者 Piskvor,

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

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

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

0
额外