如何在开发,testing和生产中pipe理数据库?
我很难find如何在开发,testing和生产服务器之间pipe理数据库模式和数据的好例子。
这是我们的设置。 每个开发者都有一个运行我们的应用程序和MySQL数据库的虚拟机。 做他们想做的事情是他们个人的沙箱。 目前,开发人员将对SQL模式进行更改,并将数据库转储到他们提交到SVN的文本文件中。
我们想要部署持续集成开发服务器,它将始终运行最新的提交代码。 如果我们现在这样做,它会从每个版本的SVN重新加载数据库。
我们有一个运行“候选版本”的testing(虚拟)服务器。 部署到testing服务器目前是一个非常手动的过程,通常需要从SVN加载最新的SQL并调整它。 另外,testing服务器上的数据不一致。 你最终将得到最后一个提交的开发者在他的沙箱服务器上的testing数据。
凡是一切破裂的是部署到生产。 由于我们无法用testing数据覆盖实时数据,因此需要手动重新创build所有模式更改。 如果有大量的模式更改或转换脚本来操纵数据,这可能会变得非常多毛。
如果问题只是模式,那么这将是一个更容易的问题,但是在开发过程中也会更新数据库中的“基础”数据,例如安全和权限表中的元数据。
这是我看到朝向持续集成和一步构build迈进的最大障碍。 你如何解决它?
后续问题:如何跟踪数据库版本,以便知道要运行哪些脚本来升级给定的数据库实例? 像Lance这样的版本表是否在标准程序下面提到?
感谢塔伦蒂诺的参考。 我不在.NET环境中,但是我发现他们的DataBaseChangeMangement wiki页面非常有帮助。 尤其是这个Powerpoint演示文稿(.ppt)
我将编写一个Python脚本,用于检查给定目录中*.sql
脚本的名称与数据库中的表,并根据构成第一部分的整数运行那些不在那里的脚本文件名。 如果这是一个非常简单的解决scheme,就像我怀疑的那样,那么我会在这里发布它。
我有一个工作脚本。 它处理初始化数据库,如果它不存在,并根据需要运行升级脚本。 还有用于擦除现有数据库和从文件导入testing数据的开关。 大约200行,所以我不会发表(尽pipe如果有兴趣,我可以把它放在pastebin上)。
有几个很好的select。 我不会使用“恢复备份”策略。
-
脚本所有架构更改,并让您的CI服务器在数据库上运行这些脚本。 有一个版本表来跟踪当前的数据库版本,只有在为较新版本的情况下才执行脚本。
-
使用迁移解决scheme。 这些解决scheme因语言而异,但对于.NET,我使用Migrator.NET。 这使您可以对数据库进行版本升级,并在版本之间上下移动。 您的模式是用C#代码指定的。
您的开发人员需要为其工作的每个错误/function编写更改脚本(模式和数据更改),而不仅仅是将整个数据库转储到源代码pipe理中。 这些脚本会将当前生产数据库升级到开发中的新版本。
您的构build过程可以将生产数据库的副本恢复到适当的环境中,并从其上运行源代码pipe理中的所有脚本,从而将数据库更新为当前版本。 我们每天都这样做,以确保所有的脚本运行正确。
看看Ruby on Rails如何做到这一点。
首先是所谓的迁移文件,基本上将数据库模式和数据从版本N转换到版本N + 1(或者在从版本N + 1降级到N的情况下)。 数据库有告诉当前版本的表。
在unit testing之前,testing数据库总是被清理干净,并且使用来自文件的固定数据填充testing数据库。
本书重构数据库:演化数据库devise可能会给你一些关于如何pipe理数据库的想法。 http://martinfowler.com/articles/evodb.html也可以阅读简短的版本;
在一个PHP + MySQL项目中,我已经将数据库修订号存储在数据库中,当程序连接到数据库时,它将首先检查修订版。 如果程序需要不同的版本,则会打开一个页面来升级数据库。 每个升级都在PHP代码中指定,这将更改数据库模式并迁移所有现有数据。
- 命名您的数据库如下 – db_dev,db_test,db_qa,db_prod(显然,你永远不应该硬编码数据库名称
- 因此,你将能够在同一台物理服务器上部署不同types的数据库(我不build议这样做,但是如果资源紧张,你可能不得不这样做)
- 确保您可以自动在这些数据之间移动数据
- 从数据库中分离数据库创build脚本=始终可以重新创build数据库并填充数据库(从旧数据库版本或外部数据源
- 不要在代码中使用硬编码连接string(甚至不在configuration文件中) – 在configuration文件中使用连接string模板,这是您dynamic填充的,每个需要重新编译的application_layer的重新configuration都是坏的
- 请使用数据库版本控制和数据库对象版本控制 – 如果您能负担得起使用现成的产品,如果不是您自己开发的东西
- 跟踪每个DDL更改并将其保存到一些历史logging表( 此处为示例 )
- 每日备份! testing你能够以多快的速度恢复从备份丢失的东西(使用自动恢复脚本
- 即使你的DEV数据库和PROD有完全相同的创build脚本,你也会遇到数据问题,所以开发人员可以创buildprod的副本并使用它(我知道我会收到这个错误,但改变思维和业务stream程将花费你less得多的时候,狗屎击中球迷 – 所以迫使编码器合法的下标,不pipe它做什么,但确保这一个
你也可以看看使用像SQL Compare这样的工具来编写不同版本的数据库之间的区别,使你能够在不同版本之间快速迁移
这是我一直不满意的东西 – 我们的解决scheme是这个问题。 几年来,我们为每个版本保留一个单独的更改脚本。 该脚本将包含上一个产品版本的变更。 每次发布应用程序时,版本号都会增加,给出如下所示的内容:
- dbChanges_1.sql
- dbChanges_2.sql
- …
- dbChanges_n.sql
直到我们开始维护两条开发线:Trunk / Mainline用于新开发,还有一个修复bug修复,短期增强等的维护分支,这一切都运行得很好。不可避免地,需要更改分支中的模式。 在这一点上,我们已经在Trunk中有了dbChanges_n + 1.sql,所以我们最终使用了如下的scheme:
- dbChanges_n.1.sql
- dbChanges_n.2.sql
- …
- dbChanges_n.3.sql
再次,这个工作得很好,直到有一天我们抬起头来,在主线上看到42个三angular洲脚本,在分支上看到了10个三angular洲脚本。 哎呀!
现在我们简单地维护一个delta脚本,并让SVN版本 – 也就是说,我们用每个版本覆盖脚本。 我们回避在分支机构中进行模式更改。
所以我也不满意 我非常喜欢Rails的迁移概念。 我对LiquiBase非常着迷。 它支持增量数据库重构的概念。 这是值得一看,我会很快详细看。 有人有经验吗? 我很好奇听到你的结果。
我们有一个非常类似于OP的设置。
开发人员使用私有数据库开发虚拟机。
[开发商不久将投入私人分支机构]
testing在不同的机器上运行(实际上在托pipe在服务器上的虚拟机上)[即将由Hudson CI服务器运行]
通过将参考转储加载到数据库中进行testing。 应用开发者模式补丁,然后应用开发者数据补丁
然后运行单元和系统testing。
生产部署作为安装者的客户。
我们所做的:
我们采用我们的沙箱DB的模式转储。 然后一个SQL数据转储。 我们将其与之前的基准进行比较。 那对deltas就是把n-1升级到n。
我们configuration转储和增量。
因此,要安装版本N CLEAN,我们运行转储到一个空的分贝。 要打补丁,应用中间补丁。
(Juha提到Rail有一个表格logging当前数据库版本的想法是一个好主意,应该使安装更新不那么令人担忧。)
三angular洲和转储必须在betatesting之前进行审查。 我看不到任何解决方法,因为我已经看到开发人员将testing帐户插入到数据库中。
查看dbdeploy ,已经有Java和.net工具了,你可以按照他们的SQL文件格式和模式版本表的标准来编写你的python版本。
恐怕我和其他的海报是一致的。 开发人员需要编写脚本。
在很多情况下,一个简单的ALTER TABLE将不起作用,您还需要修改现有的数据 – 开发人员需要了解需要什么样的迁移,并确保它们正确编写脚本(当然,您需要在某个时刻仔细testing发布周期)。
而且,如果你有任何意义,你可以让你的开发者为他们的改变脚本回滚,如果需要的话可以恢复。 这也应该被testing,以确保它们的回滚不仅没有错误地执行,而且使数据库保持与先前相同的状态(这并不总是可能的或可取的,但在大多数情况下是一个很好的规则) 。
你怎么把它挂到CI服务器上,我不知道。 也许你的CI服务器需要有一个已知的构build快照,它会在每天晚上恢复,然后应用所有更改。 这可能是最好的,否则破坏的迁移脚本不仅会打破当晚的构build,而且会破坏所有后续的构build。
如果你在.NET环境中,那么解决scheme是Tarantino 。 它在NANT构build中处理所有这些(包括要安装的SQL脚本)。
我已经写了一个工具(通过挂接到Open DBDiff )比较数据库模式,并向您build议迁移脚本。 如果你做了一个删除或修改数据的改变,它会抛出一个错误,但是为脚本提供一个build议(例如,当新模式中缺less一列时,它将检查列是否已被重命名并创buildxx – 生成包含重命名语句的script.sql.suggestion)。
http://code.google.com/p/migrationscriptgenerator/只有SQL Server我很害怕:(这也很漂亮,但是非常低摩擦(特别是如果你把它与Tarantino或http://code.google .com / p / simplescriptrunner / )
我使用它的方式是在.sln中有一个SQL脚本项目。 你也有一个本地的db_next数据库,你可以使用Management Studio或者NHibernate Schema Export或者LinqToSql CreateDatabase或者其他的东西。 然后用_dev和_next数据库执行migrationscriptgenerator,创build数据库。 用于迁移的SQL更新脚本。
我们使用命令行mysql-diff :它将两个数据库模式(来自实时数据库或脚本)之间的差异输出为ALTER脚本。 mysql-diff在应用程序启动时执行,如果模式更改,它会报告给开发人员。 所以开发人员不需要手动编写ALTER,模式更新是半自动的。
对于oracle数据库,我们使用oracle-ddl2svn工具。
这个工具自动化下一个过程
- 为每个数据库计划得到计划ddls
- 把它放在版本控制下
实例之间的更改手动解决