177

我很难找到关于如何在开发、测试和生产服务器之间管理数据库模式和数据的好例子。

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

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

我们有一个运行“候选版本”的测试(虚拟)服务器。部署到测试服务器目前是一个非常手动的过程,通常需要我从 SVN 加载最新的 SQL 并对其进行调整。另外,测试服务器上的数据不一致。您最终会得到最后一个开发人员提交的沙盒服务器上的任何测试数据。

一切都崩溃的地方是部署到生产。由于我们无法用测试数据覆盖实时数据,因此这涉及手动重新创建所有架构更改。如果有大量的模式更改或转换脚本来操作数据,这可能会变得非常棘手。

如果问题只是架构,这将是一个更容易的问题,但是数据库中还有在开发过程中更新的“基础”数据,例如安全和权限表中的元数据。

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


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


感谢您提到塔伦蒂诺。我不在 .NET 环境中,但我发现他们的DataBaseChangeMangement wiki 页面非常有帮助。特别是这个PowerPoint演示文稿(.ppt)

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


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

4

14 回答 14

55

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

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

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

于 2008-08-08T21:01:09.490 回答
28

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

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

于 2008-08-08T21:03:32.933 回答
14

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

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

测试数据库总是在单元测试之前被清除干净,并用文件中的固定数据填充。

于 2008-08-17T09:38:38.570 回答
10

Refactoring Databases: Evolutionary Database Design一书可能会给你一些关于如何管理数据库的想法。一个简短的版本也可以在http://martinfowler.com/articles/evodb.html阅读

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

于 2009-02-12T14:41:04.710 回答
5

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

于 2009-01-16T08:09:36.773 回答
5
  • 如下命名你的数据库 - dev_<<db>> , tst_<<db>> , stg_<<db>> , prd_<<db>>(显然你不应该硬编码数据库名称
  • 因此,您甚至可以在同一物理服务器上部署不同类型的数据库(我不建议这样做,但您可能必须......如果资源紧张)
  • 确保您能够在它们之间自动移动数据
  • 将数据库创建脚本与人口分开=始终可以从头开始重新创建数据库并填充它(从旧的数据库版本或外部数据源
  • 不要在代码中使用硬编码连接字符串(甚至不在配置文件中)-在配置文件中使用连接字符串模板,您会动态填充这些模板,需要重新编译的 application_layer 的每次重新配置都是不好的
  • 一定要使用数据库版本控制和数据库对象版本控制——如果你能负担得起就使用现成的产品,如果不能自己开发一些东西
  • 跟踪每个 DDL 更改并将其保存到某个历史记录表中(此处为示例
  • 每日备份!测试您能够以多快的速度恢复从备份中丢失的内容(使用自动恢复脚本
  • 即使您的 DEV 数据库和 PROD 具有完全相同的创建脚本,您也会遇到数据问题,因此请允许开发人员创建 prod 的确切副本并使用它(我知道我会收到这个的缺点,但是更改当狗屎击中粉丝时,心态和业务流程将花费您更少的成本-因此,请强制编码人员合法地订阅它所做的任何事情,但请确保这一点
于 2009-04-22T06:38:02.427 回答
4

这是我一直不满意的事情——我们对这个问题的解决方案就是这样。几年来,我们为每个版本维护了一个单独的更改脚本。此脚本将包含上一个生产版本的增量。随着应用程序的每次发布,版本号都会增加,如下所示:

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

这工作得很好,直到我们开始维护两条开发线:用于新开发的主干/主线,以及用于错误修复、短期增强等的维护分支。不可避免地,需要对分支中的模式进行更改。此时,我们已经在 Trunk 中有 dbChanges_n+1.sql,所以我们最终采用了如下方案:

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

同样,这运行得很好,直到有一天我们在主线中看到 42 个增量脚本,在分支中看到 10 个。啊!

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

所以,我对此也不满意。我真的很喜欢从 Rails 迁移的概念。我对LiquiBase非常着迷。它支持增量数据库重构的概念。值得一看,我很快就会详细了解它。有人有这方面的经验吗?我很想知道你的结果。

于 2008-08-21T02:58:16.080 回答
3

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

开发人员在带有私有数据库的 VM 中进行开发。

[开发人员将很快进入私有分支]

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

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

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

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

我们所做的:

我们获取沙盒数据库的模式转储。然后是 sql 数据转储。我们将其与之前的基线进行比较。那对增量是将n-1升级到n。

我们配置转储和增量。

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

(Juha 提到 Rail 的想法是有一个记录当前数据库版本的表是一个很好的想法,应该可以减少安装更新的烦恼。)

Delta 和转储必须在 beta 测试之前进行审查。我看不到任何解决方法,因为我看到开发人员自己将测试帐户插入数据库。

于 2008-09-02T23:30:03.217 回答
3

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

在许多情况下,一个简单的 ALTER TABLE 不起作用,您还需要修改现有数据 - 开发人员需要了解需要哪些迁移并确保它们的脚本正确(当然您需要在某些时候仔细测试发布周期)。

此外,如果您有任何意义,您还将让您的开发人员为他们的更改编写脚本回滚,以便在需要时可以恢复它们。这也应该进行测试,以确保它们的回滚不仅执行没有错误,而且使数据库保持与以前相同的状态(这并不总是可能或可取的,但在大多数情况下是一个很好的规则) .

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

于 2009-01-16T07:07:11.780 回答
1

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

于 2008-08-13T20:36:45.670 回答
1

查看dbdeploy,已经有 Java 和 .net 工具可用,您可以遵循他们的 SQL 文件布局和模式版本表标准并编写您的 python 版本。

于 2008-08-22T12:53:34.037 回答
1

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

于 2009-11-04T19:55:32.500 回答
0

我编写了一个工具(通过连接到Open DBDiff)比较数据库模式,并向您建议迁移脚本。如果您进行删除或修改数据的更改,它将引发错误,但会为脚本提供建议(例如,当新模式中缺少列时,它将检查该列是否已重命名并创建 xx - 生成script.sql.suggestion 包含重命名语句)。

http://code.google.com/p/migrationscriptgenerator/恐怕只有 SQL Server :( 它也很 alpha,但摩擦力非常低(特别是如果你将它与 Tarantino 或http://code.google结合使用.com/p/simplescriptrunner/

我使用它的方式是在你的 .sln 中有一个 SQL 脚本项目。您在本地还有一个 db_next 数据库,您可以对它进行更改(使用 Management Studio 或NHibernate Schema ExportLinqToSql CreateDatabase或其他东西)。然后使用 _dev 和 _next DB 执行 migrationscriptgenerator,这会创建。用于迁移的 SQL 更新脚本。

于 2009-02-12T14:17:41.943 回答
0

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

这个工具自动化了下一个过程

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

手动解决实例之间的更改

于 2011-03-12T14:10:41.743 回答