資料庫開發及部署策略 (C#)

作者 :Scott Mitchell

第一次部署資料驅動應用程式時,您可以將開發環境中的資料庫盲目複製到生產環境。 但在後續部署中執行盲目複本,將會覆寫輸入至生產資料庫的任何數據。 相反地,部署資料庫牽涉到將自上次部署后對開發資料庫所做的變更套用至生產資料庫。 本教學課程會檢查這些挑戰,並提供各種策略來協助記錄和套用自上次部署以來對資料庫所做的變更。

簡介

如先前教學課程所述,部署 ASP.NET 應用程式需要將相關內容從開發環境複製到生產環境。 部署不是一次性事件,而是會在每次發行新版本的軟體時或已識別並解決 Bug 或安全性考慮時發生的情況。 將 ASP.NET 頁面、映射、JavaScript 檔案和其他這類檔案複製到生產環境時,您不需要擔心自上次部署后這些檔案的變更方式。 您可以將檔案盲目複製到生產環境,並覆寫現有的內容。 不幸的是,這種簡單性不會延伸到部署資料庫。

第一次部署資料驅動應用程式時,您可以將開發環境中的資料庫盲目複製到生產環境。 但在後續部署中執行盲目複本,將會覆寫輸入至生產資料庫的任何數據。 相反地,部署資料庫牽涉到將自上次部署后對開發資料庫所做的 變更 套用至生產資料庫。 本教學課程會檢查這些挑戰,並提供各種策略來協助記錄和套用自上次部署以來對資料庫所做的變更。

部署資料庫的挑戰

第一次部署數據驅動應用程式之前,只有一個資料庫,也就是開發環境中的資料庫,這就是為什麼第一次部署數據驅動應用程式時,您可以將資料庫盲目複製到生產環境。 但部署應用程式之後,資料庫有兩個複本:一個用於開發和生產環境。

在部署之間,開發和生產資料庫可能會變得不同步。雖然生產資料庫的架構保持不變,但開發資料庫架構可能會隨著新增功能而變更。 您可以加入或移除資料列、資料表、檢視或預存程式。 此外,也可能有重要的數據會新增至開發資料庫。 許多數據驅動應用程式都包含填入硬式編碼、應用程式特定數據的查閱數據表,這些數據不可由用戶編輯。 例如,一個商品網站可能會有一個下拉式清單,其中含有描述正在舉辦之專案條件的選項:New、Like New、Good 和 Fair。 而不是直接在下拉式清單中硬式編碼這些選項,通常最好將它們放在資料庫數據表中。 如果在開發期間,將名為Poor的新條件新增至資料表,則在部署應用程式時,必須將相同的記錄新增至生產資料庫中的查閱數據表。

在理想情況下,部署資料庫會牽涉到將資料庫從開發複製到生產環境。 但請記住,在您部署應用程式並繼續開發之後,生產資料庫會填入實際使用者的實際數據。 因此,如果您只是在下一個部署中將資料庫從開發複製到生產環境,您會覆寫生產資料庫並遺失其現有的數據。 最終結果是,部署資料庫會縮小,以套用自上次部署后對開發資料庫所做的變更。

因為部署資料庫牽涉到套用架構中的變更,而且可能是上一次部署之後的數據,所以必須在部署時間 (或決定變更的歷程記錄) ,以便在生產環境中套用這些變更。 有各種不同的技術可用來管理和套用數據模型的變更。

定義基準

若要維護應用程式資料庫的變更,您需要有一些開始狀態,這是套用變更的基準。 一個極端的開始狀態可能是空的資料庫,沒有數據表、檢視或預存程式。 這類基準會導致大型變更記錄檔,因為它必須包含建立所有資料庫數據表、檢視表和預存程式,以及初始部署之後所做的任何變更。 在頻譜的另一端,您可以將基準設定為最初部署至生產環境的資料庫版本。 此選項會產生較小的變更記錄,因為它只會包含在第一次部署之後對資料庫所做的變更。 這是我偏好的方法。 當然,您可以選擇更中間的路線方法,將基準定義為初始建立資料庫與第一次部署資料庫之間的一些點。

選擇基準之後,請考慮產生可執行以重新建立基準版本的 SQL 腳本。 這類腳本可讓您快速重新建立資料庫的基準版本。 這項功能特別適用於大型專案,其中可能會有多個開發人員處理專案或其他環境,例如測試或預備環境,而每個環境都需要自己的資料庫複本。

有各種工具可供您使用,以產生基準版本的 SQL 腳本。 從 SQL Server Management Studio (SSMS) 您可以以滑鼠右鍵按單擊資料庫,移至 [工作] 子功能表,然後選擇 [產生腳本] 選項。 這會啟動文稿精靈,您可以指示產生包含 SQL 命令的檔案,以建立您的資料庫物件。 另一個選項是 [資料庫發行精靈],它不僅會產生 SQL 命令來建立資料庫架構,也會產生資料庫數據表中的數據。 在 部署資料庫 教學課程中,已詳細檢查資料庫發行精靈。 無論您使用何種工具,最後都應該會有腳本檔案,讓您可用來重新建立資料庫的基準版本,因此應該會發生此需求。

記錄 Prose 中的資料庫變更

在開發階段維護數據模型變更記錄的最簡單方式,就是記錄 prose 中的變更。 例如,如果在開發已部署的應用程式期間,將新的數據行新增至Employees數據表、從Orders數據表中移除數據行,以及將新的數據表新增 ProductCategories () ,您會使用下列歷程記錄維護文本檔或 Microsoft Word 檔案:

變更日期 變更詳細數據
2009-02-03: 已將資料intDepartmentID (、NOT NULL) 新增至Employees資料表。 已將 外鍵條件約束從 Departments.DepartmentID 新增至 Employees.DepartmentID
2009-02-05: 已從Orders數據表中移除資料行TotalWeight。 已在相關聯 OrderDetails 記錄中擷取的數據。
2009-02-12: 已建立 ProductCategories 數據表。 有三個資料行: ProductCategoryID (intNOT NULLIDENTITY) 、 CategoryName (、 NOT NULL) nvarchar(50)Active (bit) NOT NULL 。 已將主鍵條件約束新增至 ProductCategoryID,並將預設值 1 新增至 Active

此方法有一些缺點。 對於入門,沒有希望自動化。 每當需要將這些變更套用至資料庫時,例如部署應用程式時,開發人員必須手動實作每個變更,一次一次一個。 此外,如果您需要使用變更記錄從基準重新建構特定版本的資料庫,這麼做會隨著記錄的大小成長而花費更多時間。 這個方法的另一個缺點是,每個變更記錄項目的詳細度和詳細程度都會保留給記錄變更的人員。 在具有多個開發人員的小組中,某些開發人員可能會比其他開發人員更詳細、更容易閱讀或更精確的專案。 此外,可能會發生錯字和其他人為相關的數據輸入錯誤。

在 prose 中記錄資料庫變更的主要優點是簡單性。 您不需要熟悉建立和改變資料庫物件的 SQL 語法。 相反地,您可以記錄 prose 中的變更,並透過 SQL Server Management Studio 圖形使用者介面加以實作。

在 prose 中維護您的變更記錄是,可接受、不是非常複雜且無法與特定專案搭配運作,例如範圍很大、對數據模型經常進行變更,或涉及多個開發人員。 但是,我看過此方法在小型、只有偶爾變更數據模型的一人專案,以及單一開發人員在 SQL 語法中沒有強大的背景來建立和改變資料庫物件。

注意

雖然變更記錄檔中的資訊在技術上只是在部署時間之前才需要,但建議保留變更的歷程記錄。 但不要維護單一不斷成長的變更記錄檔,請考慮針對每個資料庫版本有不同的變更記錄檔。 一般而言,您會想要在每次部署資料庫時建立資料庫版本。 藉由維護變更記錄,您可以從基準開始,執行從第 1 版開始的變更記錄腳本,並繼續執行變更記錄檔腳本,直到您達到需要重新建立的版本,以重新建立任何資料庫版本。

錄製 SQL 變更語句

在 prose 中維護變更記錄的主要缺點是缺乏自動化。 在理想情況下,在部署階段對生產資料庫實作資料庫變更會像按兩下按鈕來執行腳本一樣簡單,而不需要手動執行指令清單。 藉由維護包含用來改變數據模型的 SQL 命令的變更記錄檔,就可以進行這類自動化。

SQL 語法包含數個語句,可用於建立和修改各種資料庫物件。 例如,當執行 時,CREATE TABLE 語句會建立具有指定數據行和條件約束的新數據表。 ALTER TABLE 語句會修改現有的數據表、加入、移除或修改其數據行或條件約束。 另外還有語句可用來建立、修改和卸除索引、檢視、使用者定義函數、預存程式、觸發程式和其他資料庫物件。

回到我們先前的範例映射,在開發已部署的應用程式期間,您會將新數據行新增至 Employees 數據表、從 Orders 數據表中移除數據行,然後將新的數據表新增 (ProductCategories) 。 這類動作會導致具有下列 SQL 命令的變更記錄檔:

-- Add the DepartmentID column 

ALTER TABLE [Employees] ADD [DepartmentID] 
int NOT NULL 

-- Add a foreign key constraint between Departments.DepartmentID and Employees.DepartmentID
ALTER TABLE [Employees] ADD 
CONSTRAINT [FK_Departments_DepartmentID]
      FOREIGN 
KEY ([DepartmentID]) 
      REFERENCES 
[Departments] ([DepartmentID]) 

-- Remove TotalWeight column from Orders
ALTER TABLE [Orders] DROP COLUMN 
[TotalWeight] 

-- Create the ProductCategories table

CREATE TABLE [ProductCategories]
(
      [ProductCategoryID] 
int IDENTITY(1,1) NOT NULL,
      [CategoryName] 
nvarchar(50) NOT NULL,
      [Active] 
bit NOT NULL CONSTRAINT [DF_ProductCategories_Active]  DEFAULT 
((1)),
      CONSTRAINT 
[PK_ProductCategories] PRIMARY KEY CLUSTERED ( [ProductCategoryID])
)

在部署階段將這些變更推送至生產資料庫是單鍵作業:開啟 SQL Server Management Studio、連線到生產資料庫、開啟 [新增查詢] 視窗、貼上變更記錄的內容,然後按兩下 [執行] 以執行腳本。

使用比較工具來同步處理數據模型

記錄 prose 中的資料庫變更很簡單,但實作變更需要開發人員一次對生產資料庫進行一個變更;記錄變更 SQL 命令會使在生產資料庫上實作這些變更,就像按鍵一樣簡單又快速,但需要學習和主控 SQL 語句和語法,才能建立和改變資料庫物件。 資料庫比較工具會從這兩種方法中取得最佳效果,並捨棄最差的情況。

資料庫比較工具會比較兩個資料庫的架構或數據,並顯示摘要報表,顯示資料庫的差異。 然後,按下按鈕,您就可以產生 SQL 命令來同步處理一或多個資料庫物件。 簡單地說,您可以使用資料庫比較工具來比較部署階段的開發與生產資料庫,併產生包含 SQL 命令的檔案,在執行時,會將變更套用至生產資料庫架構,使其鏡像開發資料庫架構。

有許多不同廠商提供的各種第三方資料庫比較工具。 其中一個範例是 RED Gate SoftwareSQL Compare。 讓我們逐步解說使用 SQL Compare 來比較和同步處理開發和生產資料庫架構的程式。

注意

撰寫本文時,目前的 SQL Compare 版本為 7.1 版,Standard Edition 成本為 $395。 您可以接著下載免費的 14 天試用版。

當 SQL 比較啟動 [比較專案] 對話框時,會顯示已儲存的 SQL 比較專案。 建立新專案。 這會啟動 [專案組態精靈],其會提示您比較資料庫的相關信息, (請參閱圖 1) 。 輸入開發和生產環境資料庫的資訊。

比較開發和生產資料庫

圖 1:比較開發和生產資料庫 (按兩下以檢視完整大小的映像)

注意

如果您的開發環境資料庫是網站資料夾中的 SQL Express Edition 資料庫檔案App_Data,您必須在 SQL Server Express 資料庫伺服器中註冊資料庫,才能從圖 1 所示的對話框中加以選取。 若要達成此目的,最簡單的方式是開啟 SQL Server Management Studio (SSMS) 、連線到 SQL Server Express 資料庫伺服器,以及附加資料庫。 如果您的電腦上未安裝 SSMS,您可以下載並安裝免費的 SQL Server Management Studio

除了選取要比較的資料庫之外,您也可以從 [選項] 索引標籤指定各種比較設定。您可能想要開啟的其中一個選項是「忽略條件約束和索引名稱」。回想一下,在上一個教學課程中,我們已將應用程式服務資料庫物件新增至開發和生產資料庫。 如果您使用 aspnet_regsql.exe 此工具在生產資料庫上建立這些物件,您會發現開發和生產資料庫之間的主鍵和唯一條件約束名稱不同。 因此,SQL Compare 會將所有應用程式服務數據表標示為不同。 您可以取消核取[忽略條件約束和索引名稱] 並同步處理條件約束名稱,或指示 SQL Compare 忽略這些差異。

選取要比較的資料庫 (並檢閱比較選項) 之後,請按兩下 [立即比較] 按鈕開始比較。 在接下來的數秒內,SQL Compare 會檢查兩個資料庫的架構,併產生其差異的報告。 我有目的地對開發資料庫進行了一些修改,以顯示 SQL Compare 介面中如何說明這類差異。 如圖 2 所示,我已將數據BirthDate行新增至Authors數據表、從Books數據表中移除ISBN數據行,並新增了新的數據表,Ratings這意謂著讓用戶流覽已檢閱書籍的網站費率。

注意

本教學課程中所做的數據模型變更是為了說明如何使用資料庫比較工具。 在未來的教學課程中,您將無法在資料庫中找到這些變更。

SQL 比較 清單 開發和生產資料庫之間的差異

圖 2:SQL 比較 清單 開發和生產資料庫之間的差異 (按鍵即可檢視完整大小的映射)

SQL Compare 會將資料庫物件細分為群組,快速顯示兩個資料庫中有哪些物件存在,但不同、哪些物件存在於一個資料庫中,而不是另一個資料庫中,以及哪些物件相同。 如您所見,這兩個資料庫中都有兩個物件存在,但不同: Authors 已新增數據行的數據表,以及已移除數據行的 Books 數據表。 只有一個物件存在於開發資料庫中,也就是新建立 Ratings 的數據表。 而且這兩個資料庫中有117個物件相同。

選取資料庫物件會顯示 [SQL 差異] 視窗,其中顯示這些對象的差異。 [SQL 差異] 視窗顯示在圖 2 底部,反白顯示 Authors 開發資料庫中的數據表具有 BirthDate 數據行,在生產資料庫的數據表中 Authors 找不到此數據行。

檢閱差異並選取您要同步處理的物件之後,下一個步驟是產生更新生產資料庫架構以符合開發資料庫所需的 SQL 命令。 這可透過同步處理精靈來完成。 同步處理精靈會確認要同步處理的物件,並摘要說明 (請參閱圖 3) 。 您可以立即同步處理資料庫,或使用 SQL 命令產生文稿,這些命令可在您的家中執行。

使用同步處理精靈來同步處理資料庫架構

圖 3:使用同步處理精靈來同步處理您的資料庫架構 (按鍵即可檢視完整大小的映像)

Red Gate Software s SQL Compare 之類的資料庫比較工具會盡可能輕鬆地將開發資料庫架構的變更套用至實際執行資料庫,然後按兩下即可。

注意

SQL 比較會比較和同步處理兩個資料庫 架構。 不幸的是,它不會比較和同步處理兩個資料庫數據表中的數據。 Red Gate Software 提供名為 SQL Data Compare 的產品,可比較和同步處理兩個資料庫之間的數據,但這是與 SQL Compare 不同的產品,且成本另一 $395。

在部署期間讓應用程式離線

如我們在這些教學課程中所見,部署是涉及多個步驟的程式:將 ASP.NET 頁面、主版頁面、CSS 檔案、JavaScript 檔案、映像和其他必要內容從開發環境複製到生產環境;視需要複製生產環境特定的組態資訊;並套用自上次部署后的數據模型變更。 根據檔案數目和資料庫的複雜度變更,這些步驟可能需要幾秒鐘到數分鐘才能完成。 在此時段內,Web 應用程式會處於變動狀態,且瀏覽網站的使用者可能會遇到錯誤或非預期的行為。

部署網站時,最好讓 Web 應用程式「離線」,直到部署完成為止。 讓應用程式離線 (,並在部署程式完成) 後將其備份,就像上傳檔案然後刪除一樣簡單。 從 ASP.NET 2.0 開始,只有應用程式根目錄中名為 app_offline.htm 的檔案會讓整個網站「離線」。該網站上對 ASP.NET 頁面的任何要求都會以檔案的內容 app_offline.htm 自動回應。 拿掉該檔案之後,應用程式會重新上線。

接著,在部署期間讓應用程式離線,就像在開始部署程式之前將檔案上傳 app_offline.htm 至生產環境根目錄一樣簡單,然後在部署完成後將其重新命名為其他專案) , (或將其重新命名為其他專案。 如需這項技術的詳細資訊,請參閱 John Peterson 文章:將 ASP.NET 應用程式離線

摘要

部署資料驅動應用程式的主要挑戰是部署資料庫。 因為有兩個版本的資料庫 - 一個在開發環境中,另一個是在生產環境中,這兩個資料庫架構可能會因為新功能在開發中新增時變得不同步。 更重要的是,因為實際使用者的實際數據填入生產資料庫,所以您無法使用修改的開發資料庫覆寫生產資料庫,就像在部署組成應用程式 (應用程式 ASP.NET 頁面、圖像檔等) 時一樣。 相反地,部署資料庫需要實作自從上次部署后對生產資料庫開發資料庫所做的精確變更集。

本教學課程探討維護及套用資料庫變更記錄的三種技術。 最簡單的方法是記錄 prose 中的變更。 雖然這種策略會在生產資料庫上實作這些變更,但不需要具備建立和改變資料庫物件的 SQL 命令知識。 更複雜的方法,以及在具有多個開發人員的較大專案或專案中更容易理解的方法,就是將變更記錄為一系列 SQL 命令。 這大幅加快了將這些變更推出至目標資料庫。 使用資料庫比較工具可以達到這兩種方法的最佳效果,例如 Red Gate Software s SQL Compare。

本教學課程將著重於部署數據驅動應用程式。 下一組教學課程將探討如何響應生產環境中的錯誤。 我們將探討如何顯示易記的錯誤頁面,而不是黃色的死機畫面。 我們將會瞭解如何記錄錯誤的詳細數據,以及如何在發生這類錯誤時發出警示。

快樂的程序設計!