源代码pipe理中的存储过程/数据库模式
你们是否在你select的源代码pipe理系统中跟踪存储过程和数据库模式?
当你做一个改变(添加一个表格,更新一个存储过程,你如何将改变到源代码控制?
我们在工作中使用SQL Server,并且我已经开始使用darcs进行版本控制,但是我会对一般策略以及任何方便的工具感到好奇。
编辑:哇,谢谢所有伟大的build议,家伙! 我希望我可以select多个“可接受的答案”!
我们select编写一切脚本,包括所有存储过程和模式更改。 没有wysiwyg工具,也没有花哨的“同步”程序是必要的。
架构更改非常简单,您只需为该版本创build和维护一个文件,包括所有架构和数据更改。 这将成为从版本x到x + 1的转换脚本。 然后,您可以针对生产备份运行它,并将其集成到“每日生成”中,以validation它是否正常工作。 请注意,不要更改或删除已经写入的模式/数据加载sql,因为您最终可能会破坏以后写入的任何SQL。
-- change #1234 ALTER TABLE asdf ADD COLUMN MyNewID INT GO -- change #5678 ALTER TABLE asdf DROP COLUMN SomeOtherID GO
对于存储过程,我们为每个存储过程select一个文件,并使用drop / create表单。 所有存储过程在部署时重新创build。 缺点是,如果在源代码pipe理之外进行更改,则更改将丢失。 同时,对于任何代码都是如此,但是您的DBA需要知道这一点。 这确实会阻止团队以外的人员使用存储过程,因为他们的更改会在升级过程中丢失。
使用Sql Server,语法如下所示:
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_MyProc]') and OBJECTPROPERTY(id, N'IsProcedure') = 1) drop procedure [usp_MyProc] GO CREATE PROCEDURE [usp_MyProc] ( @UserID INT ) AS SET NOCOUNT ON -- stored procedure logic. SET NOCOUNT OFF GO
唯一要做的就是编写一个实用程序来整理所有单个文件,并用整套更新(作为一个单独的脚本)创build一个新文件。 通过首先添加模式更改,然后recursion目录结构并包括所有存储过程文件来完成此操作。
作为一切脚本的好处,你将会在读写SQL方面变得更好。 您也可以使整个过程更加精细,但这是如何源代码控制所有SQL没有任何特殊的软件的基本格式。
附录:瑞克是正确的,你将失去与DROP / CREATE存储过程的权限,所以你可能需要编写另一个脚本将重新启用特定的权限。 此权限脚本将是最后运行。 我们的经验发现了ALTER和DROP / CREATE语义的更多问题。 因人而异
在Visual Studio中创build一个“数据库项目”来编写和pipe理你的sQL代码,并将项目与版本控制一起保存到解决scheme的其余部分。
我们在上一份工作中使用的解决scheme是在脚本添加到源代码控制中时对其进行编号:
01.CreateUserTable.sql
02.PopulateUserTable
03.AlterUserTable.sql
04.CreateOrderTable.sql
我们的想法是,我们总是知道运行脚本的顺序,并且如果您尝试修改脚本#1(这可能会导致#2中的INSERT失败),则可以避免pipe理可能出现的数据完整性问题。
有一件事要记住在SQL Server中的删除/创build脚本是对象级权限将会丢失。 我们改变了我们的标准,改为使用ALTER脚本来维护这些权限。
还有一些其他的注意事项,比如丢弃一个对象的事实会抛弃由sp_depends使用的依赖logging,而创build对象只会为该对象创build依赖关系。 因此,如果您删除/创build视图,则sp_depends将不再知道引用该视图的任何对象。
道德的故事,使用ALTER脚本。
我同意罗伯特·保尔森(Robert Paulson)的做法(并赞同)。 假设你正在控制一个有责任和纪律的开发团队来坚持这样的做法。
为了“强制”到我的团队,我们的解决scheme至less维护Visual Studio Team Edition for Database Professionals中的一个数据库项目。 与解决scheme中的其他项目一样,数据库项目也获得版本控制。 把数据库中的所有东西都打破成可维护的块,这是一个自然的发展过程,“一直训练”我的团队。
当然,作为一个Visual Studio项目,这是没有接近完美的地方。 你会碰到许多怪癖可能会让你感到沮丧或迷惑。 在完成任务之前,需要对项目的工作方式有一定的了解。 例子包括
- 从CSV文件中部署数据 。
- 根据构buildtypesselect性地部署testing数据 。
- 与embedded了某种types的CLR程序集的数据库相比,Visual Studio崩溃 。
- 在实现不同身份validationscheme的testing/生产数据库(SQL用户与Active Directory用户)之间没有任何区别。
但对于没有对数据库对象进行版本控制的团队而言,这是一个好的开始。 另一个着名的select当然是Red Gate的SQL Server产品套件 ,大多数使用它们的人都认为它比微软的产品更优越。
我想你应该写一个脚本,自动设置你的数据库,包括任何存储过程。 这个脚本应该放在源代码控制中。
从我的经验夫妇不同的观点。 在Oracle世界里,一切都是通过“创build”DDL脚本来pipe理的。 正如ahockley所提到的,每个对象都有一个脚本。 如果对象需要更改,则会修改其DDL脚本。 有一个包装脚本调用所有对象脚本,以便您可以将当前的数据库构build部署到任何您想要的环境。 这是主要的核心创build。
显然,在一个实时应用程序中,无论何时您推送一个需要新列的新构build,您都不会删除表并将其重新创build。 你要做一个ALTER脚本并添加列。 所以每当这种变化需要发生的时候,总会有两件事情要做:1)写出alter DDL,2)更新核心创buildDDL来反映变化。 两者都进入源代码控制,但单一的改变脚本更多的是时间点的瞬间变化,因为它只会被用来应用三angular洲。
您也可以使用像ERWin这样的工具来更新模型并转发生成的DDL,但是我知道大多数DBA不相信build模工具能够按照他们想要的方式创build脚本。 您也可以使用ERWin来定期将您的核心DDL脚本逆向工程化为模型,但是让它看上去是正确的(每次使用它的时候都是这样)。
在微软的世界里,我们采取了类似的策略,但是我们使用了红门产品来帮助pipe理脚本和增量。 仍然把脚本放在源代码pipe理中。 每个对象仍然有一个脚本(表,sproc,不pipe)。 一开始,一些DBA确实喜欢使用SQL Server GUI来pipe理对象,而不是使用脚本。 但是,随着企业的发展,企业的pipe理变得非常困难。
如果DDL在源代码控制中,使用任何构build工具(通常是ant)来编写部署脚本是微不足道的。
到目前为止,我发现最简单,最快,最安全的方法就是咬紧牙关,使用RedGate的SQL Source Control。 脚本化并存储在存储库中几分钟之内。 我只是希望RedGate把这个产品看作是一个亏损的领导者,这样它可以得到更广泛的应用。
与上面的Robert Paulson类似,我们的组织将数据库保存在源代码控制之下。 但是,我们的区别是我们试图限制我们拥有的脚本的数量。
对于任何新项目,都有一套程序。 我们在版本1有一个模式创build脚本,一个存储过程创build脚本,可能还有一个初始数据加载创build脚本。 所有的特效都保存在一个单一的,不可否认的庞大的文件中。 如果我们使用企业库,我们会包含一个用于logging的创build脚本的副本; 如果它是使用ASP.NET应用程序框架(authentication,个性化等)的ASP.NET项目,那么我们也包含该脚本。 (我们是用微软的工具生成的,然后调整它,直到它在不同的网站上以可复制的方式工作,没有趣味,但却是宝贵的时间投资。
我们使用魔法CTRL + F来find我们喜欢的过程。 :)(如果SQL Management Studio有像VS那样的代码导航,我们会很喜欢它的。)
对于后续版本,我们通常具有upgradeSchema,upgradeProc和/或updateDate脚本。 对于模式更新,我们尽可能地更改表,根据需要创build新表。 对于proc更新,我们DROP和CREATE。
这种方法出现了一个皱纹。 生成一个数据库很容易,在当前的数据库版本上很容易获得新的数据库。 但是,DAL生成(我们目前通常使用SubSonic)必须小心,以确保DB / schema / proc更改与用于访问它们的代码完全同步。 但是,在我们的构buildpath中是一个生成SubSonic DAL的batch file,因此,我们的SOP是检出DAL代码,重新运行该batch file,然后在架构和/或proc更改的任何时候检查它们。 (当然,这会触发一个源代码构build,将共享依赖关系更新到相应的DLL中)
在过去的经验中,我一直保持数据库更改的源代码,使得对于产品的每个发行版本,任何数据库更改总是被编写出来并存储在我们正在开发的版本中。 构build过程将根据数据库中存储每个“应用程序”当前版本的表自动将数据库带到当前版本。 我们编写的自定义.net实用程序应用程序将运行并确定数据库的当前版本,并按照脚本的前缀号码的顺序运行任何新脚本。 然后,我们将运行unit testing,以确保一切都很好。
我们将脚本存储在源代码pipe理中,如下所示(文件夹结构如下):
我现在对表和存储过程的命名约定有点生疏,我的例子…
[根]
[应用]
[版]
[脚本]
\脚本
我的应用程序\
1.2.1 \
001.MyTable.Create.sql
002.MyOtherTable.Create.sql
100.dbo.usp.MyTable.GetAllNewStuff.sql
通过使用将考虑应用程序和版本的版本表,应用程序将恢复每周生产备份,并且自当前版本以来运行针对数据库所需的所有脚本。 通过使用.net,我们很容易将其打包成一个事务,如果有任何失败,我们将回滚,并发送电子邮件,所以我们知道该版本有坏脚本。
所以,所有的开发人员都会确保在源代码控制中保持这种状态,所以协调的版本将确保我们计划在数据库上运行的所有脚本都能成功运行。
这可能比你所寻找的更多的信息,但它对我们来说效果很好,并且考虑到结构,很容易让所有的开发人员参与进来。
当发布date到来时,操作团队将按照发行说明从源代码控制中获取脚本,并使用我们在夜间构build过程中使用的.net应用程序对数据库运行包,这会自动将脚本包装在事务中,所以如果失败的东西会自动回滚,并没有对数据库造成影响。
如果在顶部存在drop / create语句,存储过程将获得每个sp 1个文件的标准。 视图和函数也可以获得自己的文件,所以它们更容易版本化和重用。
架构是所有1脚本开始,然后我们将做版本更改。
所有这些都存储在连接到TFS的Visual Studio数据库项目(@ work或VisualSVN Server @ home for personal stuff)中,文件夹结构如下:
– 项目
– function
– 架构
– 存储过程
– 意见
在我的公司,我们倾向于将所有数据库项目作为单独的脚本存储在源代码pipe理中,就像您对单个代码文件一样。 任何更新首先在数据库中进行,然后迁移到源代码库中,以保持更改的历史logging。
第二步,将所有数据库更改迁移到集成数据库。 这个集成数据库完全代表了生产数据库在部署后的外观。 我们还有一个QA数据库,代表当前的生产状态(或最后一次部署)。 一旦在集成数据库中进行了所有更改,我们将使用架构差异工具(Red Gate的SQL Diff for SQL Server)来生成一个脚本,将所有更改从一个数据库迁移到另一个数据库。
我们发现这是相当有效的,因为它生成了一个单一的脚本,我们可以很容易地与我们的安装程序集成。 我们经常遇到的最大问题是开发人员忘记将他们的改变转移到集成中。
我们在源代码控制中保存存储过程。
脚本的一切(对象创build等),并将这些脚本存储在源代码pipe理。 这些改变如何实现? 这是如何做事的标准做法的一部分。 需要添加一个表? 编写一个CREATE TABLE脚本。 更新sproc? 编辑存储过程脚本。
我更喜欢每个对象一个脚本。
对于特效,使用脚本包装器将特效文件写入纯文件,并应用这些文件中的更改。 如果应用正确,那么您可以检入该文件,并且也可以从该文件中重现该文件。
对于模式更改,您可能需要检入脚本以逐渐进行所做的更改。 编写脚本,应用它,然后将其签入。您可以构build一个过程,然后自动应用每个模式脚本。
我们在源代码pipe理中保留存储过程。 我们(或至less是我)做的方式是添加一个文件夹到我的项目中,为每个SP添加一个文件并手动复制,粘贴到它的代码。 所以当我更改SP时,我手动需要更改文件的源代码pipe理。
我有兴趣听到人们是否可以自动做到这一点。
我强烈build议在源代码控制中维护模式和存储过程。
保持存储过程版本允许他们回滚时,确定是有问题的。
模式是一个不太明显的答案,取决于你的意思。 维护在源代码控制中定义表的SQL,复制环境(prod / dev / user等)非常有用。
在我当前的项目中,我们一直使用另外一种方法 – 我们没有在源代码控制下获得数据库,而是在我们获得每个版本时使用数据库比较工具来编写更改。
到目前为止,它工作得很好。
我们在SCM中存储与应用程序相关的所有内容。 数据库脚本通常存储在他们自己的项目中,但是与其他代码一样被处理…devise,实现,testing,提交。
我运行一个工作将其编写成正式的目录结构。
以下是从batch file中调用的VS2005代码,命令行项目。 代码结尾的app.config键。
它基于我在网上find的其他代码。 稍微痛苦一下,但一旦你开始工作,效果很好。
Imports Microsoft.VisualStudio.SourceSafe.Interop Imports System Imports System.Configuration Module Module1 Dim sourcesafeDataBase As String, sourcesafeUserName As String, sourcesafePassword As String, sourcesafeProjectName As String, fileFolderName As String Sub Main() If My.Application.CommandLineArgs.Count > 0 Then GetSetup() For Each thisOption As String In My.Application.CommandLineArgs Select Case thisOption.ToUpper Case "CHECKIN" DoCheckIn() Case "CHECKOUT" DoCheckOut() Case Else DisplayUsage() End Select Next Else DisplayUsage() End If End Sub Sub DisplayUsage() Console.Write(System.Environment.NewLine + "Usage: SourceSafeUpdater option" + System.Environment.NewLine + _ "CheckIn - Check in ( and adds any new ) files in the directory specified in .config" + System.Environment.NewLine + _ "CheckOut - Check out all files in the directory specified in .config" + System.Environment.NewLine + System.Environment.NewLine) End Sub Sub AddNewItems() Dim db As New VSSDatabase db.Open(sourcesafeDataBase, sourcesafeUserName, sourcesafePassword) Dim Proj As VSSItem Dim Flags As Integer = VSSFlags.VSSFLAG_DELTAYES + VSSFlags.VSSFLAG_RECURSYES + VSSFlags.VSSFLAG_DELNO Try Proj = db.VSSItem(sourcesafeProjectName, False) Proj.Add(fileFolderName, "", Flags) Catch ex As Exception If Not ex.Message.ToString.ToLower.IndexOf("already exists") > 0 Then Console.Write(ex.Message) End If End Try Proj = Nothing db = Nothing End Sub Sub DoCheckIn() AddNewItems() Dim db As New VSSDatabase db.Open(sourcesafeDataBase, sourcesafeUserName, sourcesafePassword) Dim Proj As VSSItem Dim Flags As Integer = VSSFlags.VSSFLAG_DELTAYES + VSSFlags.VSSFLAG_UPDUPDATE + VSSFlags.VSSFLAG_FORCEDIRYES + VSSFlags.VSSFLAG_RECURSYES Proj = db.VSSItem(sourcesafeProjectName, False) Proj.Checkin("", fileFolderName, Flags) Dim File As String For Each File In My.Computer.FileSystem.GetFiles(fileFolderName) Try Proj.Add(fileFolderName + File) Catch ex As Exception If Not ex.Message.ToString.ToLower.IndexOf("access code") > 0 Then Console.Write(ex.Message) End If End Try Next Proj = Nothing db = Nothing End Sub Sub DoCheckOut() Dim db As New VSSDatabase db.Open(sourcesafeDataBase, sourcesafeUserName, sourcesafePassword) Dim Proj As VSSItem Dim Flags As Integer = VSSFlags.VSSFLAG_REPREPLACE + VSSFlags.VSSFLAG_RECURSYES Proj = db.VSSItem(sourcesafeProjectName, False) Proj.Checkout("", fileFolderName, Flags) Proj = Nothing db = Nothing End Sub Sub GetSetup() sourcesafeDataBase = ConfigurationManager.AppSettings("sourcesafeDataBase") sourcesafeUserName = ConfigurationManager.AppSettings("sourcesafeUserName") sourcesafePassword = ConfigurationManager.AppSettings("sourcesafePassword") sourcesafeProjectName = ConfigurationManager.AppSettings("sourcesafeProjectName") fileFolderName = ConfigurationManager.AppSettings("fileFolderName") End Sub End Module <add key="sourcesafeDataBase" value="C:\wherever\srcsafe.ini"/> <add key="sourcesafeUserName" value="vssautomateuserid"/> <add key="sourcesafePassword" value="pw"/> <add key="sourcesafeProjectName" value="$/where/you/want/it"/> <add key="fileFolderName" value="d:\yourdirstructure"/>
如果您正在寻找简单的现成解决scheme,我们的Sql Historian系统使用后台进程自动将DDL更改同步到TFS或SVN,对于任何对数据库进行更改的人都是透明的。 根据我的经验,最大的问题在于维护源代码pipe理中的代码,这是因为通常您必须依赖人员(开发人员,甚至是!)来更改工作stream程,并记住检查其更改之后他们已经在服务器上。 把这个负担放在一台机器上会使每个人的生活变得更容易。