您如何在开发,测试和生产中管理数据库?


171

我一直很难找到很好的示例,说明如何在开发,测试和生产服务器之间管理数据库模式和数据。

这是我们的设置。每个开发人员都有一个运行我们的应用程序和MySQL数据库的虚拟机。做他们想做的事是他们的个人沙箱。当前,开发人员将对SQL模式进行更改,并将数据库转储到他们提交到SVN中的文本文件中。

我们想要部署一个持续集成开发服务器,该服务器将始终运行最新的提交代码。如果我们现在这样做,它将为每个构建版本从SVN重新加载数据库。

我们有一台运行“候选发布版”的测试(虚拟)服务器。当前,部署到测试服务器是一个非常手动的过程,通常需要我从SVN加载最新的SQL并进行调整。此外,测试服务器上的数据不一致。最后,您将获得最后一个要提交的开发人员在其沙箱服务器上拥有的测试数据。

一切失败的地方就是部署到生产。由于我们无法用测试数据覆盖实时数据,因此需要手动重新创建所有架构更改。如果有大量的模式更改或转换脚本来操纵数据,那么这可能会变得很麻烦。

如果问题仅仅是模式,那将是一个更简单的问题,但是数据库中也存在“基础”数据,这些数据也在开发过程中进行了更新,例如安全性和权限表中的元数据。

这是我在迈向持续集成和一步构建的最大障碍。如何解决?


后续问题:如何跟踪数据库版本,以便知道运行哪些脚本来升级给定的数据库实例?像Lance一样的版本表是否在标准程序下面提到?


感谢您引用Tarantino。我不在.NET环境中,但是我发现他们的DataBaseChangeMangement Wiki页面非常有用。特别是此Powerpoint演示文稿(.ppt)

我将要编写一个Python脚本,该*.sql脚本将对照数据库中的表检查给定目录中的脚本名称,并根据形成文件名第一部分的整数顺序运行那些不存在的脚本名称。如果这是一个非常简单的解决方案(我怀疑会这样),那么我将在此处发布。


我有一个工作脚本。如果数据库不存在,它将处理数据库初始化,并根据需要运行升级脚本。还有一些用于擦除现有数据库和从文件导入测试数据的开关。它大约有200行,所以我不会发布(尽管有兴趣的话我可以将其放在pastebin上)。



“我将编写一个Python脚本,该脚本将对照数据库中的表检查给定目录中的* .sql脚本的名称,并根据构成第一部分的整数按顺序运行那些不存在的* .sql脚本。文件名。如果这是一个非常简单的解决方案(如我所怀疑的那样),那么我将其发布在这里。” 听起来您正在实施飞行路线。
masterxilo

Answers:


53

有几个不错的选择。我不会使用“还原备份”策略。

  1. 编写所有模式更改的脚本,并让CI服务器在数据库上运行这些脚本。有一个版本表来跟踪当前数据库的版本,并且仅当脚本用于较新的版本时才执行。

  2. 使用迁移解决方案。这些解决方案因语言而异,但是对于.NET,我使用Migrator.NET。这使您可以对数据库进行版本控制,并在不同版本之间上下移动。您的架构以C#代码指定。


28

您的开发人员需要针对他们处理的每个错误/功能编写更改脚本(模式和数据更改),而不仅仅是将整个数据库转储到源代码管理中。这些脚本会将当前的生产数据库升级到开发中的新版本。

您的构建过程可以将生产数据库的副本还原到适当的环境中,并在其上运行来自源代码管理的所有脚本,这会将数据库更新为当前版本。我们每天都会这样做,以确保所有脚本都能正确运行。


13

看看Ruby on Rails如何做到这一点。

首先,有所谓的迁移文件,它们基本上将数据库模式和数据从版本N转换为版本N + 1(或在从版本N + 1降级为N的情况下)。数据库具有表,该表告知当前版本。

在进行单元测试之前,总是擦拭干净测试数据库,并使用文件中的固定数据填充测试数据库。


10

重构数据库:演化数据库设计》一书可能会给您一些有关如何管理数据库的想法。在http://martinfowler.com/articles/evodb.html上也可以阅读简短版本

在一个PHP + MySQL项目中,我已经将数据库修订号存储在数据库中,当程序连接到数据库时,它将首先检查该修订。如果程序需要其他版本,它将打开一个页面,用于升级数据库。每次升级均以PHP代码指定,这将更改数据库架构并迁移所有现有数据。


5
  • 如下命名数​​据库- dev_<<db>> , tst_<<db>> , stg_<<db>> , prd_<<db>>(显然,您永远不应该对数据库名称进行硬编码
  • 因此,您甚至可以在同一台物理服务器上部署不同类型的数据库(我不建议这样做,但是如果资源紧张,您可能必须...)
  • 确保您能够自动在这些数据之间移动数据
  • 从填充中分离数据库创建脚本=应该总是有可能从头开始重新创建数据库并填充它(从旧数据库版本或外部数据源
  • 不要在代码中使用硬编码连接字符串(即使在配置文件中也不使用)-在配置文件中使用连接字符串模板(您会动态填充),需要重新编译的application_layer的每个重新配置都是BAD
  • 确实使用数据库版本控制和数据库对象版本控制-如果您负担得起的话,请使用现成的产品,如果不是自己开发某些产品
  • 跟踪每个DDL更改并将其保存到一些历史记录表中(此处示例
  • 每日备份!测试您能够多快地恢复备份中丢失的内容(使用自动恢复脚本)
  • 即使您的DEV数据库和PROD具有完全相同的创建脚本,您也会在数据处理上遇到问题,因此允许开发人员创建prod的确切副本并使用它(我知道我会收到与此有关的缺点,但是在思维定势和业务流程将使您的成本降低很多-因此强迫编码人员合法地进行标刻,但要确保这一点

最后一点确实是情绪。如果有必要,则表明该项目的定义已损坏。开发必须先于生产。如果生产数据产生副作用,则表明存在更大的问题。清理生产数据。如果您有理由(如您建议的那样)必须将实时数据存储在开发系统上,请与数据保护人员一起澄清最后一步,请检查这是否合法。同样,生产数据的精确副本在很大程度上减慢了开发和集成的速度。如果您负担不起这种奢侈品,请考虑采用成本更低的流程。
hakre '19

问题是,在开发过程中甚至根本无法预料到控制流中的所有极端情况以及生产中将要发生的数据质量变化。如果您的公司规模如此之大,要为此解决法律问题,则必须实施某种数据加扰和/或屏蔽解决方案,这增加了额外的复杂性,但仍必须保留导致错误的数据质量方面无论如何首先是……
Yordan Georgiev

4

这是我一直不满意的事情-我们对这个问题的解决方案。几年来,我们为每个版本维护一个单独的更改脚本。该脚本将包含上一个生产版本的增量。在该应用程序的每个发行版中,版本号都会增加,并给出以下内容:

  • dbChanges_1.sql
  • dbChanges_2.sql
  • ...
  • dbChanges_n.sql

在我们开始维护两条开发线之前,这已经足够有效了:用于新开发的Trunk / Mainline以及用于错误修复,短期增强等的维护分支。不可避免地,需要对分支中的架构进行更改。在这一点上,我们已经在主干中有了dbChanges_n + 1.sql,因此我们最终采用了以下方案:

  • dbChanges_n.1.sql
  • dbChanges_n.2.sql
  • ...
  • dbChanges_n.3.sql

再次,它运行良好,直到有一天我们查找并在主线中看到了42个增量脚本,在分支中看到了10个。啊!

如今,我们只维护一个增量脚本并让SVN版本化-即我们在每个发行版中都覆盖了该脚本。而且,我们避免在分支机构中进行架构更改。

因此,我对此也不满意。我真的很喜欢从Rails迁移的概念。我对LiquiBase非常着迷。它支持增量数据库重构的概念。值得一看,我将在稍后详细介绍。有人有经验吗?我很想知道您的结果。


4

您还可以考虑使用SQL Compare之类的工具来编写数据库不同版本之间的差异的脚本,从而使您可以在不同版本之间快速迁移


3

我们有与OP非常相似的设置。

开发人员使用私有数据库在VM中进行开发。

[开发者将很快进入私人分支机构]

测试在不同的机器上运行(实际上是在服务器上托管的VM中)[将很快由Hudson CI服务器运行]

通过将参考转储加载到数据库中进行测试。应用开发人员架构补丁,然后应用开发人员数据补丁

然后运行单元和系统测试。

生产作为安装程序部署到客户。

我们所做的:

我们对沙箱数据库进行模式转储。然后是一个sql数据转储。我们将其与先前的基准进行比较。这对增量将n-1升级为n。

我们配置转储和增量。

因此,要安装版本N CLEAN,我们将转储运行到一个空的数据库中。要打补丁,请应用中间的补丁。

(Juha提到了Rail的想法,即拥有一张记录当前数据库版本的表的想法很不错,应该减少安装更新的麻烦。)

在Beta测试之前,必须对三角洲和垃圾场进行审查。我看不到任何解决方法,因为我已经看到开发人员自己将测试帐户插入数据库。


3

恐怕我同意其他海报。开发人员需要编写更改脚本。

在许多情况下,简单的ALTER TABLE无法使用,您也需要修改现有数据-开发人员需要确定需要进行哪些迁移,并确保正确编写了脚本(当然,您需要在发布周期)。

而且,如果您有任何想法,还可以让开发人员编写脚本回滚以对其进行更改,以便在需要时可以将其还原。还应该对此进行测试,以确保它们的回滚不仅执行没有错误,而且使数据库保持与以前相同的状态(这并非总是可能或合乎需要的,但在大多数情况下是个好规则) 。

我不知道如何将其连接到CI服务器。也许您的CI服务器需要具有一个已知的构建快照,该快照将还原到每晚,然后应用此后的所有更改。那可能是最好的,否则损坏的迁移脚本不仅会破坏当晚的构建,还会破坏所有后续构建。


1

看看 dbdeploy,已经有Java和.net工具,您可以遵循它们关于SQL文件布局和架构版本表的标准,并编写python版本。


1

我们使用命令行mysql-diff:它输出两个数据库模式(来自实时数据库或脚本)之间的差异作为ALTER脚本。mysql-diff在应用程序启动时执行,如果架构发生更改,它将向开发人员报告。因此,开发人员无需手动编写ALTER,架构更新会半自动进行。



0

我编写了一个工具(通过连接到Open DBDiff)比较数据库架构,并向您建议迁移脚本。如果您进行更改以删除或修改数据,它将引发错误,但会为脚本提供建议(例如,当新架构中缺少列时,它将检查该列是否已重命名并创建xx-生成包含重命名语句的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 ExportLinqToSql CreateDatabase或其他东西)。然后,使用创建的_dev和_next数据库执行migrationscriptgenerator。用于迁移的SQL更新脚本。


0

对于oracle数据库,我们使用oracle-ddl2svn工具。

该工具可自动进行下一步

  1. 为每个数据库方案获取方案ddls
  2. 放在版本控制下

手动解决的实例之间的更改

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.