验证数据库更改(版本控制)

Posted

技术标签:

【中文标题】验证数据库更改(版本控制)【英文标题】:Verify database changes (version-control) 【发布时间】:2009-10-07 22:22:56 【问题描述】:

我已经阅读了很多关于数据库版本控制重要性的帖子。但是,我找不到一个简单的解决方案来检查数据库是否处于应有的状态。

例如,我有一个数据库,其中有一个名为“版本”的表(版本号存储在那里)。但是开发人员可以在不更改版本号的情况下访问和编辑数据库。例如,如果开发人员更新存储过程并且不更新版本数据库状态与版本值不同步。

如何跟踪这些变化?我不需要跟踪更改的内容,只需要检查数据库表、视图、过程等是否与保存在版本表中的数据库版本同步。

为什么我需要这个?在进行部署时,我需要检查数据库是否“正确”。此外,并非所有表或其他数据库对象都应被跟踪。是否可以不使用触发器进行检查?是否可以在没有 3rd 方工具的情况下完成?数据库有校验和吗?

假设我们使用 SQL Server 2005。

已编辑:

我想我应该提供更多关于我们当前环境的信息 - 我们有一个“基线”,其中包含创建基本版本所需的所有脚本(包括我们的应用程序的数据对象和“元数据”)。然而,这个“基本”版本的许多安装带有一些额外的数据库对象(额外的表、视图、过程等)。当我们对“base”版本进行一些更改时,我们还必须更新一些安装(不是全部)——那时我们必须检查“base”是否处于正确状态。

谢谢

【问题讨论】:

【参考方案1】:

您似乎违反了“Three rules for database work”的第一条和第二条规则。每个开发人员使用一个数据库并为您的架构使用一个权威来源已经很有帮助。然后,我不确定您的数据库是否有Baseline,更重要的是,您是否使用change scripts。最后,您可能会在Views, Stored Procedures and the Like 和Branching and Merging 中找到一些其他答案。

实际上,Jeff Atwood 的这篇精彩文章中提到了所有这些链接:Get Your Database Under Version Control。恕我直言,必读。

【讨论】:

嘿,没有人是完美的!我们试图改变我们的开发过程,但不是一天就能完成的。有时您必须逐步完成。 对不起 Sazug,我只是想提供有用的资源,并没有粗鲁的意思。 +1 用于提供指向"Three rules for database work" 的链接。【参考方案2】:

我们使用DBGhost 对数据库进行版本控制。创建当前数据库的脚本(连同源代码)存储在 TFS 中,然后使用 DBGhost 生成增量脚本以将环境升级到当前版本。 DBGhost 还可以为任何静态/引用/代码数据创建增量脚本。

它需要从传统方法转变思想,但这是一个很棒的解决方案,我推荐的再多也不为过。虽然它是第 3 方产品,但它可以无缝融入我们的自动化构建和部署流程。

【讨论】:

我使用 DbGhost 已经 10 年了,它从未让我失望过。他们提供的支持是首屈一指的。【参考方案3】:

我正在使用基于this codeproject article 的简单VBScript 文件为所有数据库对象生成删除/创建脚本。然后我将这些脚本置于版本控制之下。

所以要检查数据库是否是最新的或是否有尚未纳入版本控制的更改,我这样做:

从版本控制中获取最新版本的 drop/create 脚本(在我们的例子中是 subversion) 为要检查的数据库执行 SqlExtract 脚本,覆盖版本控制中的脚本 现在我可以通过我的 subversion 客户端 (TortoiseSVN) 检查哪些文件与版本控制下的版本不匹配 现在要么更新数据库,要么将修改后的脚本置于版本控制之下

【讨论】:

【参考方案4】:

您必须限制对所有数据库的访问,并且只允许开发人员访问本地数据库(他们开发的地方)和他们可以进行集成的开发服务器。最好的办法是让他们只能在本地访问他们的开发区域并通过自动构建执行集成任务。您可以使用 redgates sql compare 等工具对数据库进行比较。我建议您将所有更改保留在源代码控制(.sql 文件)下,这样您就可以了解谁在何时做了什么,以便您可以在需要时恢复数据库更改。

我还希望能够让开发人员运行本地构建脚本来重新启动他们的本地开发箱。这样他们就可以随时回滚。更重要的是,他们可以创建集成测试来测试他们的应用程序(存储库和数据访问)的管道以及以自动化方式隐藏在存储过程中的逻辑。运行初始化(重置数据库),运行集成测试(在数据库中创建绒毛),重新初始化以将数据库恢复到干净状态,等等。

如果您是 SVN/nant 风格的用户(或类似用户),并且您的存储库中只有一个分支概念,那么您可以在 DotNetSlackers 上阅读我关于此主题的文章:http://dotnetslackers.com/articles/aspnet/Building-a-***-inspired-Knowledge-Exchange-Build-automation-with-NAnt.aspx 和 http://dotnetslackers.com/articles/aspnet/Building-a-***-inspired-Knowledge-Exchange-Continuous-integration-with-CruiseControl-NET.aspx。

如果你是一个 perforce 多分支的构建大师,那么你将不得不等到我写一些关于这种自动化和配置管理的东西。

更新

@Sazug:“是的,当我们使用基本脚本 + 附加脚本时,我们会使用某种多分支构建 :) 在没有完整文章的情况下,对于这种自动化有什么基本技巧吗?”最常见的数据库有两种形式:

您在新的非生产类型环境中控制数据库(仅限活动开发人员) 一个生产环境,您可以在其中积累实时数据并在开发过程中积累

第一次设置要容易得多,并且可以从 dev 到 prod 完全自动化,并在需要时包括回滚 prod。为此,您只需要一个脚本文件夹,其中对数据库的每次修改都可以保存在 .sql 文件中。我不建议您保留 tablename.sql 文件,然后像使用 .cs 文件一样对其进行版本化,其中随着时间的推移,对该 sql 工件的更新实际上会在同一个文件中进行修改。鉴于 sql 对象彼此之间非常依赖。当您从头开始构建数据库时,您的脚本可能会遇到重大更改。出于这个原因,我建议您为每次修改保留一个单独的新文件,并在文件名的前面加上一个序列号。例如像 000024-ModifiedAccountsTable.sql 这样的东西。然后,您可以使用自定义任务或 NAntContrib 之外的其他内容,或直接执行众多 ??SQL.exe 命令行工具之一,针对从 000001-fileName.sql 到最后一个文件的空数据库运行所有脚本在 updateScripts 文件夹中。然后将所有这些脚本签入到您的版本控制中。而且由于你总是从一个干净的数据库开始,如果有人的新 sql 破坏了构建,你总是可以回滚。

在第二种环境中,自动化并不总是最佳途径,因为您可能会影响生产。如果您正在针对/针对生产环境积极开发,那么您确实需要一个多分支/环境,以便您可以在实际推动生产环境之前测试您的自动化方式。您可以使用与上述相同的概念。但是,您不能真正在 prod 数据库上从头开始,并且回滚更加困难。出于这个原因,我建议在您的构建过程中使用类似的 RedGate SQL Compare。 .sql 脚本已签入以进行更新,但您需要在运行更新之前自动执行 staging db 和 prod db 之间的差异。然后,您可以尝试同步更改并在出现问题时回滚 prod。此外,在自动推送 sql 更改之前,应采取某种形式的备份。在生产中做任何没有人眼观察的事情时要小心!如果您在所有开发/质量/暂存/性能环境中进行真正的持续集成,然后在推送到生产环境时执行一些手动步骤……那真的还不错!

【讨论】:

+1 用于限制访问。这是解决问题的关键。其他一切都只是细节。 是的,当我们使用基本脚本 + 附加脚本时,我们会使用某种多分支构建 :) 没有完整文章的那种自动化的任何基本技巧?【参考方案5】:

第一点:如果没有“规定”,就很难保持秩序。 或者以您的示例为例 - 开发人员在没有通知的情况下更改任何内容都会给您带来严重的问题。

无论如何 - 你说“不使用触发器”。 有什么具体原因吗?

如果没有,请查看 DDL 触发器。此类触发器是检查某事是否发生的最简单方法。

你甚至可以记录发生了什么。

【讨论】:

【参考方案6】:

希望有人有比这更好的解决方案,但我使用了几种方法:

有一个“主干”数据库,这是当前的开发版本。所有工作都在这里完成,因为它正准备包含在一个版本中。 每次发布​​完成时: 将上一版本的“干净”数据库复制到新版本,例如“DB_1.0.4_clean” SQL-Compare 用于将更改从主干复制到 1.0.4_clean - 这也允许准确检查包含的内容。 再次使用 SQL 比较来查找以前版本和新版本之间的差异(从 DB_1.0.4_clean 更改为 DB_1.0.3_clean),这会创建一个更改脚本“1.0.3 到 1.0.4.sql”。

我们仍在构建自动化这部分的工具,但目标是有一个表来跟踪数据库的每个版本,以及是否应用了更改脚本。升级工具会查找最新条目,然后逐个应用每个升级脚本,最终数据库处于最新版本。

我没有这个问题,但是保护 _clean 数据库不被其他团队成员修改是微不足道的。此外,由于我事后使用 SQL 比较来生成更改脚本,因此开发人员无需随时跟踪它们。

我们实际上做了一段时间,这是一个巨大的痛苦。很容易忘记,同时进行了一些未必成功的更改 - 因此使用单独创建的更改脚本创建的完整升级脚本有时会添加一个字段,然后将其删除,全部在一个版本。如果有索引更改等,这显然会很痛苦。

关于 SQL 比较的好处是它生成的脚本是在一个事务中 - 如果失败,它会回滚整个事情。因此,如果生产数据库以某种方式被修改,升级将失败,然后部署团队可以实际使用生产数据库上的 SQL 比较与 _clean 数据库,并手动修复更改。我们只需要这样做一两次(该死的客户)。

.SQL 更改脚本(由 SQL Compare 生成)存储在我们的版本控制系统(subversion)中。

【讨论】:

【参考方案7】:

如果您有 Visual Studio(特别是数据库版本),则可以创建一个 Database Project 并将其指向 SQL Server 数据库。该项目将加载模式并基本上为您提供许多其他功能。它的行为就像一个代码项目。它还为您提供了为整个表格和内容编写脚本的优势,因此您可以将其保存在 Subversion 下。 构建项目时,它会验证数据库是否具有完整性。很聪明。

【讨论】:

【参考方案8】:

在我们的一个项目中,我们将数据库版本存储在数据库中。

对数据库结构的每个更改都被编写到单独的 sql 文件中,除了所有其他更改之外,该文件还会增加数据库版本。这是由更改数据库结构的开发人员完成的。

部署脚本检查当前数据库版本和最新更改脚本,并在必要时应用这些 sql 脚本。

【讨论】:

【参考方案9】:

首先,开发人员应该无法访问您的生产数据库,或者开发人员(和其他所有人)应该受到严格的指示,即不得在变更控制系统之外对生产系统进行任何类型的更改。

变更控制在您期望工作的任何系统中都至关重要(在整个系统中涉及 >1 名工程师的情况下)。

每个开发者都应该有自己的测试系统;如果他们想对此进行更改,他们可以,但是系统测试应该在一个更可控的系统测试系统上进行,该系统具有与生产相同的更改 - 如果你不这样做,你就不能依赖发布工作,因为它们正在不兼容的环境中进行测试。

进行更改时,应创建并测试适当的脚本,以确保它们完全适用于当前版本,并且回滚有效*

*你在写回滚脚本,对吧?

【讨论】:

我们正在转向开发人员无法访问生产数据库的过程,但很难显示在测试版本中开发的好处,而不是在无法自动完成时升级实时版本。当然,在实时版本中开发要容易得多,但并不安全。回滚脚本仅适用于架构更改,不适用于“元数据”更改?不,还没有回滚脚本... 回滚脚本应该适用于任何更改。如果您需要将回滚脚本打包为 shell 脚本或小程序,请执行此操作。顺便说一句,尝试使数据库架构更改“向后兼容”是最简单的,这样您就可以升级数据库,保留旧的应用程序服务器,然后再升级它们。否则,您最终会进行多步骤部署和大量 icky 测试。【参考方案10】:

我同意其他关于开发人员不应有权更改生产数据库的帖子。开发人员要么应该共享一个通用的开发数据库(并冒着互相踩踏的风险),要么他们应该拥有自己的个人数据库。在前一种情况下,您可以使用 SQL Compare 之类的工具部署到生产环境。在后一种情况下,您需要在开发生命周期中定期同步开发者数据库,然后再升级到生产环境。

在 Red Gate,我们很快将发布一个新工具,即 SQL 源代码控制,旨在简化此过程。我们将集成到 SSMS 中,只需单击一个按钮即可在源代码控制中添加和检索对象。如果您有兴趣了解更多信息或注册我们的抢先体验计划,请访问此页面:

http://www.red-gate.com/Products/SQL_Source_Control/index.htm

【讨论】:

只是一个更新:SQL Source Control 1.0 已经发布。这会将您的开发数据库与 SVN 或 TFS 链接起来。 red-gate.com/products/SQL_Source_Control/index.htm【参考方案11】:

我必须同意这篇文章的其余部分。数据库访问限制将解决生产问题。然后使用 DBGhost 或 DVC 等版本控制工具将帮助您和团队的其他成员维护数据库版本控制

【讨论】:

以上是关于验证数据库更改(版本控制)的主要内容,如果未能解决你的问题,请参考以下文章

数据库模式更改是不是应该增加语义版本控制中的主要版本?

AEM 6.5 中的版本控制元数据更改

在没有打开版本控制的情况下更改了核心数据模型

Mozilla FireFox页面根据身份验证类型控制更改

Tableau 的版本控制

语义版本控制对参数名称更改意味着啥?