微軟給我們提供了一種非常好用的數據庫遷移方案,但是我發現周圍的同學用的並不多,所以我還是想把這個方案整理一下。.NET選手看過來,特別是還在通過手工執行腳本來遷移數據庫的同學們,當然你也可以選擇EF的Migration方案和FluentMigrator,但是下面我介紹的這種方案符合我對團隊協作的所有要求,對開發者而言使用起來非常方便,不容易犯錯。
一、方案目標
一個好的數據庫遷移方案在我看來需要滿足以下條件:
1、適用於每個開發者擁有自己獨立的數據庫開發環境,用於不同feature的並行開發
2、能夠配合版本控制工具,不同的版本能夠方便合併和易於解決衝突
3、數據庫開發環境要易於在不同的版本之間切換
4、易於跟CI工具集成,不同的開發環境(Dev,QA,Staging,Product)能夠部署不同的數據庫開發環境
5、DBA能夠方便審覈開發人員提交的數據庫腳本
6、整個數據庫的遷移過程由腳本自動化完成,不應該有人工干涉
二、準備
假設我們有一個數據庫blog,該數據庫中包含一個表Users,數據庫初始腳本:
Create Database Blog GO USE [Blog] GO /****** Object: Table [dbo].[Users] Script Date: 2016/7/31 17:18:09 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Users]( [Id] [int] IDENTITY(1,1) NOT NULL, [UserName] [nvarchar](200) NULL, [Email] [nvarchar](100) NULL, [Age] [int] NULL, CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
如圖所示,我們得到了一個初始的數據庫版本:
三、新建數據庫遷移解決方案
1、打開vs, 我用的是vs2015
2、如圖所示,新建工程
3,在Blog.Database工程,右鍵,選擇Schema Compare…
4、點擊中間的“交換位置”圖標,左邊代表源(Source),右邊代表目標(Destination)。我們現在要本地數據庫把schema更新在我們新建的數據庫工程中。
5、在“源”中選擇Select source
6、按照下圖所示添加數據庫連接
7、Compare 然後Update,數據庫中的schema將會同步在我們的vs解決方案中
四、添加存儲過程
至此爲止我們已經添加了對Blog數據庫的遷移方案,所有開發人員對數據庫的更改都要通過該解決方案來完成。
比如開發者A這時候需要添加第一個存儲過程:
1、在dbo目錄下新建Stored Procedures文件夾
2、新建存儲過程腳本GetUser.sql
編寫以下存儲過程:
-- ============================================= -- Author: <Author,,Name> -- Create date: <Create Date,,> -- Description: <Description,,> -- ============================================= CREATE PROCEDURE GetUser AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here SELECT TOP 100* FROM Users END
腳本已經編寫完畢,這時候開發者A需要把這個更改更新到本地的數據庫中:
這時候“源”是我們的數據庫遷移方案,目標是本機的數據庫,compare然後update
以git爲例,開發人員此時會把Blog.Database解決方案更改合併到develop分支,其他開發人員通過compare-update操作將別人對數據庫的更改update到本地。
五、更改表結構
開發人員B在另一個分支需要對錶User添加兩列:Gender和Description,直接在解決方案中打開User表做更改
當然最後要通過Compare-Update操作將更改應用到本地數據庫,其他開發人員也會通過相同的方式將此更改應用在本地。
六、添加Reference Data
開發人員添加了一個表Gender,並且需要添加三條固定數據:
在Tables文件夾下右鍵-Tabel-Gender
這時候需要添加三條固定數據:Male,Female,Unknown,這時候要用到PostDeploymentSql:
1、新建PostDeploymentSql
2、新建Gender.sql
3、(重要)此時要在Gender.sql右鍵,Builder Action-None,否則無法編譯
4、在Gender.sql添加下面的Sql,這個sql在每次部署的時候都要執行,所以一定是“冪等”的:
PRINT 'Beginning Deployment Gender table...' IF EXISTS (select top 1 1 from dbo.Gender where Value='01') update dbo.Gender set Name='Male' where Value='01' else insert dbo.Gender(value,Name) values('01','Male') IF EXISTS (select top 1 1 from dbo.Gender where Value='02') update dbo.Gender set Name='Female' where Value='02' else insert dbo.Gender(value,Name) values('02','Female') IF EXISTS (select top 1 1 from dbo.Gender where Value='03') update dbo.Gender set Name='Unknown' where Value='03' else insert dbo.Gender(value,Name) values('03','Unknown') PRINT 'Finishing Deployment Gender table...'
5、在Script.PostDeployment.sql中編寫下面的腳本:
PRINT 'Running Post-Deploy Scripts' :r .\Gender.sql --append other sql scripts PRINT 'End Post-Deploy Scripts'
6、Compare-Update,將此更改更新到本地數據庫
此時你會發現本地數據庫添加了Gender表,但是我們添加的三條數據並沒有進來,這是因爲Script.PostDeployment.sql並沒有執行,這個腳本只有在發佈的時候才能執行。
七、添加publish文件
通過上面的步驟我們可以看出來,我們每次都是先更改數據庫遷移解決方案,然後通過Compare和Update操作將更新同步到本地,但是這樣操作存在兩個缺點:
1、Script.PostDeployment.sql並沒有執行,無法將ReferenceData同步在數據庫
2、只適用於同步本地數據庫,其他環境需要採用一些自動化的方式來完成,而不是手工compare,update,避免人工操作失誤
通過下面的步驟來添加publish文件
1、在Blog.Database工程上右鍵-publish
接下來要添加數據庫連接,然後添加Create Profile,最後點擊publish。
通過Create Profile添加了一個xml的publish文件,重命名爲:Local.publish.xml。
我們可以通過雙擊此xml文件完成對本地數據庫的publish操作
八、自動化publish數據庫遷移方案到其他數據庫環境
我們通過手工publish將更改應用到本地,但是其他環境(Dev,QA,Staging,Prod)則要通過腳本來完成。
1、在本地新建一個空數據庫Blog_QA用來模擬QA的數據庫環境
2、採用之前的步驟新建一個publish文件,該publish文件的數據庫爲Blog_QA,將該xml文件重命名爲:Blog_QA.publish.xml
在Blog_QA.publish.xml右鍵,屬性,Copy To Output Directory:Copy Always
3、通過sqlpackage程序要遷移數據庫
運行命令行:cd 到C:\Program Files (x86)\Microsoft SQL Server\110\DAC\bin目錄
執行命令:SqlPackage.exe /Action:Publish /SourceFile:G:\SourceCode\Blog.Database\bin\Debug\Blog.Database.dacpac
/Profile:G:\SourceCode\Blog.Database\bin\Debug\Publish\Blog_QA.publish.xml
通過編寫腳本來完成不同環境的數據庫遷移。
該方案的核心在於:所有開發人員通過維護vs數據庫工程來完成對數據庫的更改,最後通過publish工具來完成數據庫遷移,同時我們可以通過sqlpackage工具來完成自動化遷移。
整個demo提供下載:https://git.oschina.net/richieyangs/Blog.Database.git
由於數據庫連接字符串的不同,所以不能直接使用demo中的publish文件來完成數據庫遷移。大家根據自己的情況做出修改。