SQL Compare是一款比较和同步SQL Server数据库结构的工具。现有超过150,000的数据库管理员、开发人员和测试人员在使用它。当测试本地数据库,暂存或激活远程服务器的数据库时,SQL Compare将分配数据库的过程自动化。html
咱们的团队为商业组织开发实际应用程序;主要是格鲁吉亚银行。这些应用程序基于MS SQL Server做为数据库的.Net-Windows-Forms应用程序。它们具备许多业务逻辑,这些逻辑包含在数据库例程中,例如存储过程、函数、视图和SQL CLR。sql
绝不奇怪,考虑到客户业务的性质,咱们没有访问客户数据库或数据进行开发、测试或部署的权限。在TFS源代码管理下,咱们只有开发数据库及其人工测试数据。开发人员在本身的数据库副本上工做,每一个副本都有本身的示例数据,而且他们使用Redgate SQL Source Control提交开发更改。而后,咱们使用SQL Compare命令行来自动化数据库部署。在本文中,我将解释如何实现此目标,并举例说明如何比较相同或不一样分支中的数据库的两个修订版,并生成部署脚本。数据库
在源代码管理中管理数据库服务器
咱们的数据库源代码控制和分支策略很简单。咱们在Trunk中拥有最新的代码库;整个应用程序都在那里,包括其中的数据库部分。全部新功能和错误修复最初都在Trunk中进行。咱们建立的每一个分支只是Trunk的一个副本,所以表明了代码库的完整时间点状态。在应用了一些更改并签入Trunk以后,咱们能够根据须要将其合并到这些分支中的任何一个。一般,这是为了修复已报告的错误,但当对咱们的客户来讲很重要时,咱们还须要可以合并小的功能更改。例如,并不是每一个客户都能负担得起部署每一个版本的费用,所以他们部署的版本一般落后三个或四个版本。可是,他们仍然须要咱们为当前版本部署紧急修复程序,偶尔会使用一些“专有”功能。架构
那么,当咱们开发软件时,这一切如何工做?让咱们将其称为“under-source-control-application”(简称USCAPP)。咱们在USCAPP_Trunk中拥有最新的代码库,并在TFS分支下提供了一些发行版本,称为v241、v242等。app
直接或经过合并进行的全部更改均可以经过Trunk及其分支的普通TFS检入完成。在每次签入时,TFS都会建立一个称为变动集的东西,它具备惟一的参考号。变动集表示源代码管理中整个代码库的快照。像任何其余源代码控制系统同样,TFS能够针对任何给定的变动集编号,为任何修订生成代码库的时间点状态。ide
固然,对于集合中的全部TFS项目(包括其分支机构),TFS变动集编号都是全局的,而且每次对该项目集合进行每次检入时,TFS变动集编号都将逐渐增长。对咱们来讲,这意味着USCAPP_Trunk及其全部分支v24一、v242等都共享相同的、全球的、不断增加的变动集号。函数
开发人员进行更改,每一个人都在本身的专用数据库上工做,并经过SQL Source Control签入更改,这些更改将更新USCAPP_Trunk中的代码。根据须要,咱们将所需的变动集合并到其余分支,在这些分支中建立新的变动集。所以,假设最新版本为v245,而且咱们知道客户A已将v242部署到生产环境中。该客户尚不能升级到最新版本,但已部署了一个附加的升级脚本以修复一些错误并进行一些小的改进。换句话说,客户A正在运行很是特定的v242版本,咱们能够将其转换为TFS变动集编号,该编号惟一地标识其已部署的分支v242的代码库的时间点状态。工具
使用SQL Compare命令行自动生成更改脚本测试
咱们的目标是使生成同步SQL脚本的过程自动化,该脚本覆盖自上次发布脚本以来发生的全部更改。
假设客户A已经部署了分支v242,而且该数据库的发行版本标记有人类可读的版本号2.4.2.0,该版本号对应于变动集编号87300,即它是在变动集87300是当前最新版本时发布的代码库的全局变动集编号。
此后一个月过去了,咱们已经在数据库中进行了更改,如今TFS中当前的更改集数量为88100。如今,咱们要生成一个脚本,其中包含当月所作的每一个更改,所以将数据库的v2.4.2.0升级到变动集编号88100表示的状态,咱们将其称为v2.4.2.1。
为此,咱们须要从TFS中检索数据库的两个时间点状态,一个表明源数据库(不会改变),另外一个表明目标数据库(咱们要升级)。所以,对于客户A,变动集88100表明源,而87300表明目标。咱们须要比较这两种状态以找出差别,而后生成一个脚本以同步目标,以便其状态与源相同。对于两个数据库中都存在但有差别的任何数据库对象,必须更改目标中对象的定义以匹配其在源中的定义。应该建立源中存在但目标中不存在的任何对象,应该删除目标中存在但源中不存在的任何对象。
好消息是,咱们没必要手动执行此操做。SQL Compare GUI和SQL Compare命令行均支持此功能。咱们但愿使该过程自动化,所以咱们使用命令行并将适当的参数传递给该命令行以生成同步脚本。咱们还须要仔细记录该脚本将数据库的2.4.2.0版本升级到v2.4.2.1。固然,这里咱们也须要一些保护措施。其中一项是检查,该检查将中止在不是v2.4.2.0的任何数据库上运行此脚本。在这里,我不会进行演示,可是最后,我将更详细地讨论这些需求。
比较同一分支中的两个修订
首先,我将描述咱们如何发布称为“修复”的脚本,该脚本主要用于部署一些错误修复和较小的改进。主要版本保持不变。
咱们使用SQL Compare命令行进行此操做,传递一个XML参数文件(argfile),该文件包含指示SQL Compare如何执行比较的全部必需命令行开关的值。或者,您能够指定每个到命令行的开关,或在PowerShell中“splat”参数。
在这种状况下,惟一须要传递给SQL Compare的参数是XML Argfile的合格文件名,称为“shared.xml”
“%programfiles(x86)%\ Red Gate \ SQL Compare 13 \ sqlcompare” /Argfile:"shared.xml“
argfile的内容应彻底按照SQL Compare命令行的在线文档中的说明填写。这是真实的示例:
<commandline> <SourceControl1 /> <Revision1>88100</Revision1> <SourceControl2 /> <Revision2>87300</Revision2> <Options>NoDeploymentLogging,IgnoretSQLt,IgnoreFillFactor,IgnoreWhiteSpace,IgnoreFileGroups,IgnoreUserProperties,IgnoreWithElementOrder,IgnoreDatabaseAndServerName,CaseSensitiveObjectDefinition,ObjectExistenceChecks,DropAndCreateInsteadofAlter,ForceColumnOrder,DoNotOutputCommentHeader,IgnoreUsersPermissionsAndRoleMemberships</Options> <ScriptsFolderXML>Command Line\SourceControlAddress v242.xml</ScriptsFolderXML> <Filter>Command Line\Filters\Shared.scpf</Filter> <ReportType>Interactive</ReportType> <Report>Command Line\Output\Shared.html</Report> <ScriptFile>Command Line\Output\Shared.sql</ScriptFile> <Force /> <Verbose /> </commandline>
Argfile包含五个命令行开关,咱们使用它们来定义所需的行为。/ Sourcecontrol1和/ Sourcecontrol2切换指定咱们的源,和目标,是源控制脚本的一个文件夹,在这种状况下,版本分别为88100和87300。
<SourceControl1 /> <Revision1>88100</Revision1> <SourceControl2 /> <Revision2>87300</Revision2>
所述<ScriptsFolderXML>开关包含完整的文件路径为XML文件,SourceControlAddress v242.xml。该文件以下所示,包含分支v242的数据库的源代码控制地址:
<?xml version="1.0" encoding="utf-16" standalone="yes"?> <ISOCCompareLocation version="1" type="TfsLocation"> <ServerUrl>http://tfs:8080/tfs/projects</ServerUrl> <SourceControlFolder>$/USCAPP/Branches/v242/Database/Schema</SourceControlFolder> </ISOCCompareLocation>
这是SQL Compare应从中恢复87300和88100变动集的地址。当执行SQL Compare的命令行版本时,它将把这些变动集还原为“脚本文件夹”(在撰写本文时,还原到Windows Temp中的文件夹中),并使用88100做为源和87300做为目标进行比较,以生成最终的升级脚本。
比较两个不一样分支中的数据库
咱们用来发布已经在Trunk中完成的全部新功能的过程与错误修正版本稍有不一样,可是主要概念保持不变。一样在这种状况下,咱们必须比较数据库架构的两个不一样状态。即便它们的“真理来源”做为TFS源代码管理中的版本存在,它们也被导出到文件夹,做为Redgate称为“脚本文件夹”的东西。而后能够将它们做为两个数据库模式进行比较。在这种状况下,不一样之处在于咱们不是在一个TFS分支中比较由变动集表示的两个修订版(或时间点状态),而是在如今表示版本的两个分支之间进行比较。
要逐步进行:该过程首先从Trunk分支中建立一个新分支,并为其指定一个适当的名称。例如,若是v2.4.2是USCAPP应用程序的最后发行版本,那么在发行该版本时,咱们已经建立了一个名为v242的分支。如今,咱们已经对Trunk进行了更多更改,从逻辑上讲,咱们将发布v2.4.3版本,所以咱们的新分支将称为v243,从那时开始,就其所包含的内容而言,它将做为Trunk分支的确切副本。
如今,咱们应该比较两个单独分支的两个变动集。咱们用于比较的变动集必须是刚刚建立的新v243分支的变动集,而且是客户A已应用的上一个分支v242的最新发布的部署脚本所对应的变动集。此比较将揭示仅在Trunk的数据库上发生的更改,而上一个分支v242的数据库中缺乏这些更改。
为此,咱们须要指定一个而不是两个源代码管理文件夹位置,一个用于包含源/ ScriptsFolderXML1的TFS分支,另外一个用于包含目标/ ScriptsFolderXML2的分支。咱们使用SQL Compare保留关键字“HEAD”来指定咱们想要源分支的最新的源控件更改集。生成的Argfile以下所示:
<commandline> <SourceControl1 /> <Revision1>HEAD</Revision1> <SourceControl2 /> <Revision2>88100</Revision2> <Options>NoDeploymentLogging,IgnoretSQLt,IgnoreFillFactor,IgnoreWhiteSpace,IgnoreFileGroups,IgnoreUserProperties,IgnoreWithElementOrder,IgnoreDatabaseAndServerName,CaseSensitiveObjectDefinition,ObjectExistenceChecks,DropAndCreateInsteadofAlter,ForceColumnOrder,DoNotOutputCommentHeader,IgnoreUsersPermissionsAndRoleMemberships</Options> <ScriptsFolderXML1>Command Line\SourceControlAddress v243.xml</ScriptsFolderXML1> <ScriptsFolderXML2>Command Line\SourceControlAddress v242.xml</ScriptsFolderXML2> <Filter>Command Line\Filters\Shared.scpf</Filter> <ReportType>Interactive</ReportType> <Report>Command Line\Output\Shared.html</Report> <ScriptFile>Command Line\Output\Shared.sql</ScriptFile> <Force /> <Verbose /> </commandline>
这是目标的源代码管理脚本位置XML文件(SourceControlAddress v242.xml):
<?xml version="1.0" encoding="utf-16" standalone="yes"?> <ISOCCompareLocation version="1" type="TfsLocation"> <ServerUrl>http://tfs:8080/tfs/projects</ServerUrl> <SourceControlFolder>$/USCAPP/Branches/v242/Database/Schema</SourceControlFolder> </ISOCCompareLocation>
这是源代码之一(SourceControlAddress v243.xml):
<?xml version="1.0" encoding="utf-16" standalone="yes"?> <ISOCCompareLocation version="1" type="TfsLocation"> <ServerUrl>http://tfs:8080/tfs/projects</ServerUrl> <SourceControlFolder>$/USCAPP/Branches/v243/Database/Schema</SourceControlFolder> </ISOCCompareLocation>
再一次,咱们仅使用Argfile的地址做为惟一参数来调用SQL Compare命令行:
“%programfiles(x86)%\ Red Gate \ SQL Compare 13 \ sqlcompare” /Argfile:"shared.xml“
在SQL Compare命令行完成其工做以后,在“Shared.sql” 文件中,咱们有了能够在目标数据库上运行的升级脚本,以将其升级到最新的主要版本。
进一步要求
在现实生活中,咱们始终须要仔细检查自动生成的脚本,添加检查和控件,以确保例如以正确的顺序将全部必需的升级脚本应用到预期的数据库版本。咱们还须要对SQL Compare的自动生成的部署脚本进行少许添加和自定义,例如处理数据插入或向每一个脚本添加标头信息(建立脚本时,版权信息,联系信息等)。 或在每一个自动生成的脚本的末尾附加一些动态生成的SQL脚本,以识别客户。
经过使用自定义迁移脚本修改SQL Compare部署,能够实现不少这样的目标,尽管实际上咱们遇到了一些困难,例如它们减慢了SQL Source Control的运行速度或部署前和部署后脚本。
对咱们来讲,另外一个须要考虑的因素是,SQL Compare迁移和部署前或部署后脚本是静态的,而咱们的要求是动态生成的脚本。相反,咱们在Visual Studio中构建了一个简单,轻便的工具,容许开发人员对SQL Compare脚本进行小的动态添加和自定义。
我避免在这里进行深刻研究的另外一个复杂性是,对于咱们的每一个客户,咱们的源代码管理干线将客户数据库的全部共享逻辑与包含该组织专有的定制代码的小型例程结合在一块儿。在本文中,我演示了如何使用SQL Compare命令行来部署全部客户通用的数据库结构和代码。尽管该过程与特定于客户的例程基本相同,可是须要进行一些小的调整,以确保始终将独有功能仅部署到该客户的生产数据库中,而且没有任何客户能够看到专门为另外一位客户编写的逻辑。我将在下一篇文章中描述咱们如何实现这一目标!
结论
咱们的经验是Redgate Source Control和SQL Compare能够协同工做,而且对咱们自动化脚本生成过程起到了很大的做用。SQL Compare容许对其从Git或TFS源代码控制中提取脚本的方式进行很是精细的控制,从而为咱们节省了大量手动脚本编写。咱们将看到可以自动生成相应的回滚(降级)脚本以及升级脚本的更多可能性。它只须要反转咱们用于源和目标的变动集并启动SQL Compare命令行便可!它是一种多功能工具。
本教程内容到这里就结束了,但愿对您有所帮助~