关于mysql:如何在开发,测试和生产中管理数据库?

关于mysql:如何在开发,测试和生产中管理数据库?

How do you manage databases in development, test, and production?

我一直很难尝试找到有关如何在开发,测试和生产服务器之间管理数据库架构和数据的良好示例。

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

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

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

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

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

这是我看到的朝着持续集成和一步构建的最大障碍。您如何解决?

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

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

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

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


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

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

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


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

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


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

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

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


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

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


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

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


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

    • 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十分着迷。它支持增量数据库重构的概念。值得一看,我将在稍后详细介绍。有人有经验吗?我很想知道您的结果。


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

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

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

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


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

    开发人员使用私有DB在VM中进行开发。

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

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

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

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

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

    我们所做的:

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

    我们配置转储和增量。

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

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

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


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


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


    如果您在.NET环境中,则解决方案是Tarantino。它在NANT构建中处理所有这些(包括要安装的SQL脚本)。


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

    该工具可自动进行下一步

  • 为每个数据库方案获取方案ddls
  • 放在版本控制下
  • 手动解决的实例之间的更改


    我编写了一个工具(通过连接到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 Export或LinqToSql CreateDatabase等)。然后,使用创建的_dev和_next数据库执行migrationscriptgenerator。用于迁移的SQL更新脚本。


    推荐阅读