資料庫通常不能夠與它們支持的應用程序保持同步,從管理方面來講,將資料庫和數據置於一個已知狀態是個很大的挑戰。在本期的 讓開發自動化 中,自動化專家 Paul Duvall 演示了如何使用開源的 LiquiBase 資料庫遷移工具輕鬆地處理資料庫和應用程序的頻繁變更。
在過去幾年中,我使用過的大多數應用程序都是需要管理大量數據的企業應用程序。從事這類項目的開發團隊常常將資料庫視為與應用程序完全脫離的單獨實體。造成這種現象的原因是組織結構經常將資料庫團隊從應用程序開發團隊分離出來。有時候,這是團隊的習慣引起的。不管怎樣,我發現這種分離會導致(或忽略)一些實踐:
這些實踐效率低下,使開發人員無法與數據變更保持同步。而且,還使應用程序的用戶 遇到與數據不一致和數據損壞等問題。
圖 1 演示了軟體開發項目中經常用到的手工方法。手工方法在使用時通常不能保證一致性並且容易產生錯誤,撤銷已完成的工作很困難,而且難以分析資料庫變更的歷史。例如,某個 DBA 可能想變更查找數據,但是開發人員卻忘記將這個數據插入到同一個表中。
|
通過實現最小化人為干預的資料庫變更策略,可以避免手工方法帶來的缺陷。通過結合各種實踐和工具,可以使用一致且可重複的過程變更資料庫和數據。在本文中,我將介紹以下內容:
在圖 2 中,一個 Build/Continuous Integration 伺服器輪詢版本控制庫(例如子版本)中的變更。當它發現一個變更后,將運行一個自動化構建腳本,該腳本使用 LiquiBase 更新資料庫。
通過使用類似圖 2 所示的過程,團隊中的任何人都可以將相同的變更應用到資料庫中 — 可以是本地或共享資料庫伺服器。此外,由於這個過程使用了自動化腳本,因此這些變更不需要任何人為干預就可以應用到不同環境中。
|
使用 LiquiBase 管理資料庫變更
LiquiBase(從 2006 年開始投入使用)是一種免費開源的工具,可以實現不同資料庫版本之間的遷移(參見 參考資料)。目前也存在少量其他開源資料庫遷移工具,包括 openDBcopy 和 dbdeploy。LiquiBase 支持 10 種資料庫類型,包括 DB2、Apache Derby、MySQL、PostgreSQL、Oracle、Microsoft® SQL Server、Sybase 和 HSQL。
要安裝 LiquiBase,下載經過壓縮的 LiquiBase Core 文件,解壓縮,然後將包含的 liquibase-version.jar 文件放到系統路徑中。
要開始使用 LiquiBase,需要以下四個步驟:
創建一個變更日誌和變更集
要運行 LiquiBase,如清單 1 所示,首先要創建一個 XML 文件,也稱為資料庫變更日誌:
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.7" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.7 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.7.xsd"> <changeSet id="2" author="paul"> <createTable tableName="brewer"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> </column> <column name="name" type="varchar(255)"> <constraints nullable="false"/> </column> <column name="active" type="boolean" defaultValue="1"/> </createTable> </changeSet> </databaseChangeLog> |
|
可以看到,資料庫變更日誌文件包括一個 XML 模式引用(LiquiBase 安裝中包含的 dbchangelog-1.7.xsd 文件)。我在變更日誌文件中創建了一個 <changeSet>。在 <changeSet> 中,我使用結構化的方式將變更應用到資料庫,如 LiquiBase 模式所定義。
從命令行運行 LiquiBase
定義完變更集后,可以從命令行運行 LiquiBase,如清單 2 所示:
liquibase --driver=org.apache.derby.jdbc.EmbeddedDriver \ --classpath=derby.jar \ --changeLogFile=database.changelog.xml \ --url=jdbc:derby:brewery;create=true \ --username= --password= \ update |
在本例中,運行 LiquiBase 傳入的內容:
最後,清單 2 調用 update 命令告訴 LiquiBase 將變更應用到資料庫中。
在自動構建中運行 LiquiBase
這裡並不使用命令行選項,通過調用 LiquiBase 提供的 Ant 任務,可以將資料庫變更作為自動化構建的一部分。清單 3 展示了 Ant 任務的示例:
<target name="update-database"> <taskdef name="updateDatabase" classname="liquibase.ant.DatabaseUpdateTask" classpathref="project.class.path" /> <updateDatabase changeLogFile="database.changelog.xml" driver="org.apache.derby.jdbc.EmbeddedDriver" url="jdbc:derby:brewery" username="" password="" dropFirst="true" classpathref="project.class.path"/> </target> |
在清單 3 中,創建了一個名為 update-database 的目標。在其中定義了一個將要用到的特殊 LiquiBase Ant 任務,稱為 updateDatabase。我傳入需要的值,包括 changeLogFile(指定 清單 1 中定義的變更日誌文件)和資料庫的連接信息。classpathref 中定義的類路徑必須包含 liquibase-version.jar。
運行前後
圖 3 展示了在 清單 1 中運行變更集之前的資料庫狀態:
圖 4 展示了運行資料庫變更集的結果,可以通過命令行(如 清單 2 所示)或從 Ant(如 清單 3 所示)運行:
查看 完整的圖。
需要注意圖 4 中的幾個方面。創建了兩個特定於 LiquiBase 的表,以及一個根據 清單 1 中的變更集定義創建的新表。第一個特定於 LiquiBase 的表稱為 databasechangelog,它跟蹤應用到資料庫的所有變更 — 有助於跟蹤誰執行了資料庫變更以及原因。第二個特定於 LiquiBase-的表是 databasechangelock,標識出具有資料庫變更鎖的用戶。
還可以使用多種其他方式運行 LiquiBase,但我已經介紹了應用資料庫變更所需的大部分信息。在使用 LiquiBase 時,將花很多時間研究應用資料庫重構的各種方法,以及變更特定資料庫的複雜性。例如,LiquiBase 提供了數據回滾支持,這可能是個很大的挑戰。在展示資料庫重構示例之前,我將快速瀏覽一些資料庫集成的基本原則和實踐,它們能幫助您充分利用資料庫遷移。
頻繁集成資料庫變更
最近幾年,開發團隊將類似於處理源代碼的原則和實踐應用到資料庫資產管理中。因此,可以將資料庫變更編寫為腳本、在一個源代碼庫中共享這些資產,以及將變更集成到構建和持續集成過程,這只是自然的演進。表 1 概括了開發團隊將資料庫變更變成一個自動化過程的一部分時,需要遵循的關鍵實踐:
|
實踐 | 說明 |
---|---|
腳本化所有 DDL 和 DML | 資料庫變更應該能夠從命令行運行。 |
數據資產的源代碼控制 | 使用一個版本控制庫管理所有與資料庫相關的變更。 |
本地資料庫沙盒 | 每個開發人員使用一個本地資料庫沙盒執行變更。 |
自動化資料庫集成 | 將資料庫相關的變更作為構建過程的一部分。 |
這些實踐確保了更好的一致性並防止變更在軟體版本轉換之間丟失。
對現有資料庫應用重構
隨著新特性添加到了應用程序中,經常需要變更資料庫的結構或修改表約束。LiquiBase 提了超過 30 種資料庫重構支持(參見 參考資料)。本節將介紹 4 種重構:添加列(Add Column)、刪除列(Drop Column)、創建表(Create Table)和操作數據。
添加列
在項目的開始,幾乎不可能考慮到資料庫中的所有列。而有時候,用戶要求新的特性 — 例如為存儲在系統中的信息收集更多的數據 — 這就要求添加新的列。清單 4 使用 LiquiBase addColumn 重構,向資料庫中的 distributor 表添加了一個列:
<changeSet id="4" author="joe"> <addColumn tableName="distributor"> <column name="phonenumber" type="varchar(255)"/> </addColumn> </changeSet> |
新的 phonenumber 列被定義為 varchar 數據類型。
刪除列
假如在以後幾個版本中,您想要刪除在清單 4 添加的 phonenumber 列。只需要調用 dropColumn 重構,如清單 5 所示:
<dropColumn tableName="distributor" columnName="phonenumber"/> |
創建表
向資料庫添加一個新表也是常見的資料庫重構。清單 6 創建了一個新表 distributor,定義了列、約束和默認值:
<changeSet id="3" author="betsey"> <createTable tableName="distributor"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> </column> <column name="name" type="varchar(255)"> <constraints nullable="false"/> </column> <column name="address" type="varchar(255)"> <constraints nullable="true"/> </column> <column name="active" type="boolean" defaultValue="1"/> </createTable> </changeSet> |
這個示例使用了 createTable 資料庫重構作為變更集的一部分(清單 1 中也使用了 createTable)。
操作數據
在應用了結構性數據重構后(例如添加列和創建表),通常需要向受重構影響的表中插入數據。此外,可能需要修改查找表(或其他類型的表)中的現有數據。清單 7 展示了如何使用一個 LiquiBase 變更集插入數據:
<changeSet id="3" author="betsey"> <code type="section" width="100%"> <insert tableName="distributor"> <column name="id" valueNumeric="3"/> <column name="name" value="Manassas Beer Company"/> </insert> <insert tableName="distributor"> <column name="id" valueNumeric="4"/> <column name="name" value="Harrisonburg Beer Distributors"/> </insert> </changeSet> |
您應該編寫用於操作數據的 SQL 腳本,因為使用 LiquiBase XML 變更集限制很多。有時候使用 SQL 腳本向資料庫應用大量的變更會簡單一些。LiquiBase 也可以支持這些情景。清單 8 調用變更集中的 insert-distributor-data.sql 來插入 distributor 表數據:
<changeSet id="6" author="joe"> <sqlFile path="insert-distributor-data.sql"/> </changeSet> |
LiquiBase 支持很多其他資料庫重構,包括 Add Lookup Table 和 Merge Columns。可以使用如清單 4 到清單 8 所示的方式定義所有這些支持。
持續保持數據同步
在軟體開發中,如果遇到一些難題,您應該更多地關注它,而不是等到以後才手動執行這些操作,從而使問題變得更嚴重,花費也更大。資料庫遷移非常重要,自動化遷移過程能夠獲得很多好處。在本文中,我已經介紹了以下內容:
表 2 總結了 LiquiBase 提供的一些特性的列表:
特性 | 說明 |
---|---|
支持多個資料庫 | 支持 DB2、Apache Derby、MySQL、PostgreSQL、Oracle、Microsoft SQL Server、Sybase 和 HSQL 等。 |
查看應用到資料庫的變更的歷史。 | 使用 databasechangelog 表,可以查看應用到資料庫的每一個變更。 |
生成資料庫差異日誌 | 了解 LiquiBase 變更集以外的應用到資料庫的變更。 |
能夠運行定製 SQL 腳本 | 使用 LiquiBase 調用已經編寫好的 SQL 腳本。 |
回滾資料庫變更的工具 | 可以對應用到資料庫的任何變更執行回滾。 |
可以看到,通過自動化腳本恰當地應用變更時,資料庫遷移變得更加輕鬆,並且成為團隊中的多數成員都可以運行的重複過程。(責任編輯:A6)
[火星人 ] 讓開發自動化: 實現自動化資料庫遷移已經有1143次圍觀