跟踪数据库模式更改的机制
跟踪和/或自动化数据库模式更改的最佳方法是什么? 我们的团队使用Subversion进行版本控制,并且我们已经能够以这种方式自动化我们的一些任务(将构build到临时服务器,将testing代码部署到生产服务器),但是我们仍然在手动进行数据库更新。 我希望find或创build一个解决scheme,使我们能够跨不同环境的服务器高效地工作,同时继续使用Subversion作为后端,通过它将代码和数据库更新推送到各种服务器。
许多stream行的软件包包括检测数据库版本并应用必要更改的自动更新脚本。 这是甚至在更大规模(跨多个项目,有时多个环境和语言)上做到这一点的最好方法吗? 如果是的话,是否有任何现有的代码简化了stream程,或者最好是推出我们自己的解决scheme? 有没有人实现过类似的东西,并将其集成到Subversion post-commit挂钩中,或者这是一个坏主意?
虽然支持多种平台的解决scheme是可取的,但我们绝对需要支持Linux / Apache / MySQL / PHP堆栈,因为大部分工作都在该平台上。
在Rails的世界里,有一个迁移的概念,在这个脚本中,数据库的变化是在Ruby中进行的,而不是数据库特有的SQL风格。 您的Ruby迁移代码最终被转换为您当前数据库特有的DDL; 这使得切换数据库平台非常容易。
对于您对数据库所做的每一项更改,都会编写一个新的迁移。 迁移通常有两种方法:应用更改的“向上”方法和取消更改的“向下”方法。 单个命令使数据库保持最新状态,也可用于将数据库引导至特定的模式版本。 在Rails中,迁移被保存在项目目录的自己的目录中,并像其他任何项目代码一样进入版本控制。
这篇Oracle Rails迁移指南涵盖了很好的迁移。
使用其他语言的开发人员已经考虑过迁移,并已经实现了自己的语言特定版本。 我知道Ruckusing ,一个PHP迁移系统,仿照Rails的迁移; 这可能是你在找什么。
我们使用类似于bcwoord的东西来保持我们的数据库模式跨5个不同的安装(生产,分期和一些开发安装)同步,并在版本控制中备份,它工作得很好。 我会详细说明一下:
为了同步数据库结构,我们有一个脚本,update.php和一些编号为1.sql,2.sql,3.sql等的文件。脚本使用一个额外的表来存储当前的版本号数据库。 N.sql文件是手工制作的,从版本(N-1)到版本N的数据库。
它们可以用来添加表,添加列,将数据从旧的格式迁移到新的列格式,然后删除列,插入“主”数据行,如用户types等。基本上,它可以做任何事情,并有适当的数据迁移脚本永远不会丢失数据。
更新脚本的工作原理是这样的:
- 连接到数据库。
- 做一个当前数据库的备份(因为东西会出错)[mysqldump]。
- 创build簿记表(称为_meta),如果它不存在。
- 从_meta表读取当前版本。 假设0没有find。
- 对于编号高于VERSION的所有.sql文件,请按顺序执行它们
- 如果其中一个文件产生错误:回滚到备份
- 否则,将簿记表中的版本更新为执行的最高.sql文件。
一切都进入源代码pipe理,每个安装都有一个脚本,用一个脚本执行(使用适当的数据库密码调用update.php)来更新到最新版本。 我们SVN通过自动调用数据库更新脚本的脚本更新分段和生产环境,因此代码更新随附必要的数据库更新。
我们也可以使用相同的脚本从头重新创build整个数据库; 我们只需删除并重新创build数据库,然后运行将完全重新填充数据库的脚本。 我们也可以使用这个脚本填充一个空的数据库进行自动化testing。
build立这个系统只需要几个小时,它在概念上很简单,每个人都可以获得版本编号scheme,并且具有向前推进和发展数据库devise的能力,而无需通信或手动执行修改在所有数据库上。
当从phpMyAdmin粘贴查询时要小心! 那些生成的查询通常包括数据库名称,你肯定不想要,因为它会打破你的脚本! 就像CREATE TABLE mydb
。 如果系统上的数据库没有被调用mydb, newtable
(…)将会失败。 我们创build了一个预注释的SVN钩子,它将禁止包含mydb
string的.sql文件,这是一个肯定的迹象,表明有人从phpMyAdmin复制/粘贴没有适当的检查。
我的团队编写了所有数据库更改的脚本,并将这些脚本提交给SVN,以及每个应用程序版本。 这允许数据库的增量更改,而不会丢失任何数据。
从一个版本到另一个版本,您只需要运行一组更改脚本,并且您的数据库是最新的,并且您仍然拥有所有数据。 这可能不是最简单的方法,但它绝对有效。
这里的问题确实让开发人员很容易将他们自己的本地更改编写到源代码控制中,以便与团队共享。 我已经遇到了这个问题很多年了,并且受到了Visual Studio for Database专业人员的function的启发。 如果你想要一个具有相同function的开源工具,试试这个: http : //dbsourcetools.codeplex.com/玩得开心 – Nathan。
如果您仍然在寻找解决scheme:我们正在提出一个名为neXtep designer的工具。 这是一个数据库开发环境,您可以将整个数据库置于版本控制之下。 你在一个版本控制库上工作,每一个变化都可以被跟踪。
当您需要发布更新时,您可以提交组件,产品将自动生成以前版本的SQL升级脚本。 当然,你可以从任何2个版本生成这个SQL。
然后你有很多select:你可以把这些脚本放到你的SVN中,并用你的应用代码,这样它就可以被现有的机制部署了。 另一个select是使用neXtep的传递机制:脚本被导出到一个被称为“传递包”(SQL脚本+ XML描述符)的东西中,安装程序可以理解这个包并将其部署到目标服务器,同时确保一致性,依赖性检查,注册安装的版本等
该产品是GPL,基于Eclipse,因此它可以在Linux,Mac和Windows上运行。 它也支持Oracle,Mysql和Postgresql(DB2支持正在进行中)。 看看维基,你会发现更多的详细信息: http : //www.nextep-softwares.com/wiki
Scott Ambler撰写了一系列关于数据库重构的系列文章(并共同撰写了一本书 ),认为您应该基本上应用TDD原则和实践来维护您的模式。 您为数据库设置了一系列结构和种子数据unit testing。 然后,在您更改任何内容之前,您可以修改/编写testing以反映该更改。
我们已经这样做了一段时间,似乎工作。 我们编写代码来在unit testing套件中生成基本的列名和数据types检查。 我们可以随时重新运行这些testing,以validationSVN签出中的数据库是否与应用程序实际运行的活动数据库匹配。
事实certificate,开发人员有时也会调整他们的沙盒数据库,而忽略在SVN中更新模式文件。 然后代码依赖于尚未签入的数据库更改。这种错误可能非常难以确定,但testing套件将立即提取。 如果您将其内置到一个更大的持续集成计划中,这将特别有用。
这是一个有点低技术,可能有更好的解决scheme,但你可以将你的模式存储在一个SQL脚本,可以运行创build数据库。 我想你可以执行一个命令来生成这个脚本,但是我不知道这个命令是不幸的。
然后,将脚本与代码一起提交到源代码控制中。 当您需要随代码一起更改模式时,可以将脚本与需要更改的模式的代码一起签入。 然后,脚本上的差异将指示模式更改的差异。
有了这个脚本,你可以将它与DBUnit或某种构build脚本集成在一起,所以它看起来可以适应已经自动化的过程。
如果您使用C#,请查看Subsonic,一个非常有用的ORM工具,但也会生成sql脚本来重新创build您的scheme和\或数据。 这些脚本可以放在源代码pipe理中。
将您的架构转储到一个文件并将其添加到源代码pipe理。 然后一个简单的差异会告诉你什么改变。
K. Scott Allen在模式版本上有一两篇不错的文章,它使用了其他答案中引用的增量更新脚本/迁移概念; 见http://odetocode.com/Blogs/scott/archive/2008/01/31/11710.aspx 。
我已经在Visual Studio中使用了以下数据库项目结构来处理几个项目,并且工作得很好:
数据库
更改脚本
0.PreDeploy.sql
1.SchemaChanges.sql
2.DataChanges.sql
3.Permissions.sql
创build脚本
存储过程
function
查看
然后,我们的构build系统通过按以下顺序执行脚本,将数据库从一个版本更新到下一个版本:
1.PreDeploy.sql
2.SchemaChanges.sql
创build脚本文件夹的内容
2.DataChanges.sql
3.Permissions.sql
每个开发人员通过将代码附加到每个文件的末尾来检查特定错误/function的变化。 一旦主要版本完成并在源代码pipe理中分支,“更改脚本”文件夹中的.sql文件的内容将被删除。
我们使用一个非常简单但有效的解决scheme。
对于新安装,我们在存储库中有一个metadata.sql文件,它包含所有数据库模式,然后在构build过程中我们使用这个文件来生成数据库。
对于更新,我们在硬编码的软件中添加更新。 我们坚持硬编码,因为我们不喜欢在问题真正成为问题之前解决问题,迄今为止这种问题并没有被certificate是一个问题。
所以在我们的软件中,我们有这样的东西:
RegisterUpgrade(1, 'ALTER TABLE XX ADD XY CHAR(1) NOT NULL;');
这段代码将检查数据库是否在版本1中(存储在自动创build的表中),如果数据库已过期,则执行该命令。
要更新存储库中的metadata.sql,我们在本地运行此升级,然后提取完整的数据库元数据。
唯一经常发生的事情就是忘记提交metadata.sql,但这不是一个大问题,因为它容易在构build过程中testing,而且唯一可能发生的事情就是使用一个过时的数据库,并在第一次使用时升级它。
此外,我们不支持降级,但它是通过devise,如果更新中断,我们恢复了以前的版本,并在重新尝试之前修复更新。
我创build了以生成版本命名的文件夹,并将升级和降级脚本放在那里。 例如,您可以有以下文件夹:1.0.0,1.0.1和1.0.2。 每个脚本都包含允许您在不同版本之间升级或降级数据库的脚本。
如果客户或客户在1.0.1版本中遇到问题,并且正在使用1.0.2,则将数据库恢复到其版本不会成为问题。
在你的数据库中,创build一个名为“schema”的表,在这个表中放入当前版本的数据库。 然后写一个程序,可以升级或降级你的数据库很容易。
就像Joey说的,如果你在Rails世界里,使用Migrations。 🙂
对于我目前的PHP项目,我们使用rails migrations的思想,我们有一个migrations目录,其中我们保留文件标题“migration_XX.sql”,其中XX是迁移的编号。 目前这些文件是在更新时手动创build的,但是它们的创build可以很容易修改。
然后我们有一个名为“Migration_watcher”的脚本,正如我们在pre-alpha中那样,当前在每个页面加载上运行,并检查是否有一个新的migration_XX.sql文件,其中XX大于当前的迁移版本。 如果是这样,它会运行所有migration_XX.sql文件对数据库最大的数字,瞧! 架构更改是自动的。
如果你需要恢复系统的能力,需要进行大量的调整,但是这很简单,并且对于我们这个相当小的团队来说工作得非常好。
我build议使用Ant(跨平台)作为“脚本”方面(因为它实际上可以通过jdbc与任何db通信)和Subversion的源代码库。 在进行更改之前,Ant会让您将数据库“备份”到本地文件。 1.通过Ant将现有的数据库模式备份到文件2.通过Ant将版本控制版本控制到Subversion版本库3.通过Ant向数据库发送新的SQL语句
Toad for MySQL有一个称为模式比较的function,允许您同步2个数据库。 这是我迄今为止使用的最好的工具。
恕我直言迁移确实有一个巨大的问题:
从一个版本升级到另一个版本可以正常工作,但是如果你有数百个表格和长期的修改历史(如我们所做的那样),那么重新安装一个给定的版本可能会花费很长时间。
从基线到现在的版本(为数百个客户数据库)运行整个历史的三angular洲可能需要很长时间。
我喜欢Yii如何处理数据库迁移。 迁移基本上是一个实施CDbMigration
的PHP脚本。 CDbMigration
定义了一个包含迁移逻辑的up
方法。 也可以实施一种倒退方法来支持迁移的逆转。 或者,可以使用safeUp
或safeDown
来确保迁移是在事务的上下文中完成的。
Yii的命令行工具yiic
包含对创build和执行迁移的支持。 迁移可以一个接一个或一个批次应用或反转。 创build迁移将为实现CDbMigration
的PHP类生成代码,该代码根据用户指定的时间戳和迁移名称进行唯一命名。 之前应用于数据库的所有迁移都存储在迁移表中。
有关更多信息,请参阅手册中的“ 数据库迁移”一文。
尝试db-deploy – 主要是一个Java工具,但也适用于PHP。
有一个命令行的mysql-diff工具比较数据库模式,其中模式可以是磁盘上的实时数据库或SQL脚本。 对于大多数模式迁移任务来说都是好事。