本系列文章目錄
資料庫開發的持續整合 - Sql Server 部署升級工具
資料庫開發的持續整合 - Sql Server資料庫結構比較
資料庫開發的持續整合 - 方法和流程
資料庫開發的持續整合 - Liquibase的簡介和應用
資料庫的持續整合 - CruiseControl.Net的項目配置
在資料庫開發的持續整合-方法和流程中,談到了在持續整合中應用Liquibase,這裡簡單介紹一下,然後說說Liquibase在持續整合過程中的具體應用方法。
Liquibase簡介
Liquibase是一個用於跟蹤、管理和應用程式資料庫變化的開源的資料庫重構工具。它將所有資料庫的變化(包括結構和資料)都儲存在XML檔案中,便於版本控制。
Liquibase具備如下特性:
* 不依賴於特定的資料庫,目前支援包括Oracle/Sql Server/DB2/MySql/Sybase/PostgreSQL/Caché等12種資料庫,這樣在資料庫的部署和升級環節可協助應用系統支援多資料庫。
* 提供資料庫比較功能,比較結果儲存在XML中,基於該XML你可用Liquibase輕鬆部署或升級資料庫。
* 以XML儲存資料庫變化,其中以作者和ID唯一標識一個變化(ChangSet),支援資料庫變化的合并,因此支援多開發人員同時工作。
* 在資料庫中儲存資料庫修改曆史(DatabaseChangeHistory),在資料庫升級時自動跳過已應用的變化(ChangSet)。
* 提供變化應用的復原功能,可按時間、數量或標籤(tag)復原已應用的變化。通過這種方式,開發人員可輕易的還原資料庫在任何時間點的狀態。
* 可產生資料庫修改文檔(HTML格式)
* 提供資料重構的獨立的IDE和Eclipse外掛程式
Liquibase的核心就是儲存變化的XML,如例:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.6"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.6
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.6.xsd">
<changeSet id="1" author="bob">
<createTable tableName="department">
<column name="id" type="int">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(50)">
<constraints nullable="false"/>
</column>
<column name="active" type="boolean" defaultValue="1"/>
</createTable>
</changeSet>
</databaseChangeLog>
其中,changeSet包含不同的資料庫變化,幾乎涵蓋了所有的資料庫變化類型,具體支援的類型要看API,我這裡給幾個例子:
* 建立和刪除表、視圖、預存程序、主鍵、外鍵、索引等
* 重新命名表、視圖、列等
* 加入列預設值、唯一約束、非空約束等
* 合并兩個列
* 在一個表的資料的基礎上建立一個字典表
除此之外,Liquibase還允許你運行自己的Sql指令碼、執行Shell程式。
之所以所說”幾乎涵蓋“,是因為目前我發現不支援使用者自訂資料和自訂函數的。由於在我新的資料庫開發原則中摒棄了對他們的依賴,所以也不痛苦。
Liquibase在持續整合中的應用
如果你基於Java開發,你可能會更喜歡Liquibase,如果基於Ruby On Rails開發,你可能會選擇Migration 和 Rake。我基於.Net,考察過Red Gate($),Migration.Net, Machine.Migrations,Power Tools等等,最終還是選擇了Liquibase。如何整合到我的開發流程中來,我選擇命令列以及基於命令列的MsBuild任務。
用命令列搞一個bat檔案執行Liquibase,使用者資料庫部署(見我例子中的deploy.bat)。
Msbuild提供比較、部署、文檔產生等等全套功能,用於開發的全過程,當然也用於CC.Net(見例子中的ci.proj)。
具體的應用程式套件括:
* 開發人員在本地完成一個階段的開發後,使用ci.proj中的diff target比較本機資料和基準資料,產生changelog.xml,提交到SVN(這裡,XML檔案中的changeSet中的Author取開發人員本地機器的使用者名稱)
* CC.Net檢測到SVN的變化,觸發持續整合過程,調用ci.proj中的deploy在一個測試資料庫中建立最新的資料結構,然後對實體類和訪問層進行測試(開發人員在本地機器的測試亦如此)。測試成功,使用ci.proj中的doc產生文檔,發布在持續整合伺服器的IIS中。
* 如果是trunk項目則在測試完成後需要在SVN上打Tag,然後使用ci.proj中的publish發行集資料庫部署升級程式(含changelog.xml)
* 發布的資料庫部署升級程式中含deploy.bat給部署人員用以部署或升級現有的產品系統資料庫。
關於changelog.xml的合并:
* 每一次開發人員有新的changelog.xml提交,我會通過SVN的Merge功能將其新的changeSet合并
* 這個過程可以通過SVN自動完成,但鑒於資料庫的變化影響面太大,需要謹慎審核,因此還是選擇手工來做
關於test.proj: 這是用MsBuild寫的一個測試案例,測試ci.proj提供的資料庫比較和升級功能。
關於ci.proj的說明:
* 對dtproperties的特殊處理
一旦你使用過Sql Server的企業管理器操作過資料庫,會自動產生這個表存一些資料庫物件的屬性。雖然在企業管理器中顯示為系統資料表,但它的object_id很大,使得liquibase將其看做使用者表,會影響資料庫比較結果,因此在ci.proj中會檢查參與比較的兩個資料是否存在該表,如果不存在則建立它。
* <Target Name="CheckExec">
MsBuild使用Java命令列調用liquibase,如果執行出錯,MsBuild不能得到該錯誤,這樣將導致CC.Net的持續整合在失敗時報成功。沒有找到更好的辦法,我將執行Java得到的輸出寫入exec.log檔案,然後用CheckExec檢查其中是否有Failed關鍵字。可能還有其他的關鍵字需要檢查,如果園友發現還請告訴我。
<Target Name="CheckExec">
<ReadLinesFromFile File="$(ExecLog)" >
<Output TaskParameter="Lines" PropertyName="ExecOutput"/>
</ReadLinesFromFile>
<Message Text="$(ExecOutput)" Importance="high"/>
<StringComparison Comparison="Contains" Param1="$(ExecOutput)" Param2="Failed" >
<Output TaskParameter="Result" PropertyName="StringSearchResult"/>
</StringComparison>
<Delete Files="$(ExecLog)"/>
<Error Text="liquibase report error" Condition="$(StringSearchResult)"/>
</Target>
附件:持續整合專案檔
Update20080718 發現Liquibase應用SQL Server產生修改記錄的兩個Bug:
* 刪除一個定義了外鍵(引用其他表)的列時,刪除Constraint的指令碼放在了刪列的指令碼後面,導致部署失敗
* 添加NotNull的Constraint是,指令碼中少了columnDataType,多了defaultNullValue,導致部署失敗