讓開發自動化: 實現自動化資料庫遷移

火星人 @ 2014-03-12 , reply:0


  
資料庫通常不能夠與它們支持的應用程序保持同步,從管理方面來講,將資料庫和數據置於一個已知狀態是個很大的挑戰。在本期的 讓開發自動化 中,自動化專家 Paul Duvall 演示了如何使用開源的 LiquiBase 資料庫遷移工具輕鬆地處理資料庫和應用程序的頻繁變更。

在過去幾年中,我使用過的大多數應用程序都是需要管理大量數據的企業應用程序。從事這類項目的開發團隊常常將資料庫視為與應用程序完全脫離的單獨實體。造成這種現象的原因是組織結構經常將資料庫團隊從應用程序開發團隊分離出來。有時候,這是團隊的習慣引起的。不管怎樣,我發現這種分離會導致(或忽略)一些實踐:

  • 手工變更資料庫
  • 不能與團隊的其他成員分享資料庫變更
  • 使用不一致的方法變更資料庫或數據
  • 使用低效的手工方法管理資料庫版本之間的變更

這些實踐效率低下,使開發人員無法與數據變更保持同步。而且,還使應用程序的用戶 遇到與數據不一致和數據損壞等問題。

圖 1 演示了軟體開發項目中經常用到的手工方法。手工方法在使用時通常不能保證一致性並且容易產生錯誤,撤銷已完成的工作很困難,而且難以分析資料庫變更的歷史。例如,某個 DBA 可能想變更查找數據,但是開發人員卻忘記將這個數據插入到同一個表中。

關於本系列

作為開發人員,我們致力於用戶自動化流程;但許多開發人員卻疏忽了自動化自己的開發流程。為此,我們編寫了 讓開發自動化 系列文章,專門探討軟體開發流程自動化的實踐應用,為您介紹何時 以及如何 成功應用自動化。


圖 1. 手工變更資料庫

通過實現最小化人為干預的資料庫變更策略,可以避免手工方法帶來的缺陷。通過結合各種實踐和工具,可以使用一致且可重複的過程變更資料庫和數據。在本文中,我將介紹以下內容:

  • 使用一種稱為 LiquiBase 的工具在各個資料庫版本之間進行遷移
  • 如何自動運行資料庫遷移
  • 一致地變更資料庫的實踐
  • 使用 LiquiBase 進行資料庫重構

在圖 2 中,一個 Build/Continuous Integration 伺服器輪詢版本控制庫(例如子版本)中的變更。當它發現一個變更后,將運行一個自動化構建腳本,該腳本使用 LiquiBase 更新資料庫。


圖 2. 自動化資料庫遷移

通過使用類似圖 2 所示的過程,團隊中的任何人都可以將相同的變更應用到資料庫中 — 可以是本地或共享資料庫伺服器。此外,由於這個過程使用了自動化腳本,因此這些變更不需要任何人為干預就可以應用到不同環境中。

DDL、DML 模式、資料庫或數據

在本文中,我使用術語資料庫變更 表示通過應用數據定義語言(Data Definition Language,DDL)腳本變更資料庫結構。(一些資料庫供應商將之稱為模式)。同時,我將通過數據定義語言(DML)腳本變更資料庫稱為數據 變更。

使用 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,需要以下四個步驟:

  1. 創建一個資料庫變更日誌(change log)文件。
  2. 在變更日誌文件內部創建一個變更集(change set)。
  3. 通過命令行或構建腳本對資料庫運行變更集。
  4. 檢驗資料庫中的變更。

創建一個變更日誌和變更集

要運行 LiquiBase,如清單 1 所示,首先要創建一個 XML 文件,也稱為資料庫變更日誌:


清單 1. 在 LiquiBase 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

有些開發人員會使用 XML,而其他人則沒有涉足這個領域。很多開發人員甚至已經習慣使用 XML 腳本進行編程(例如,使用 Apache Ant),但是 DBA 不一定用到。最近,我非常興奮地向一個 DBA 同事展示 LiquiBase 的一些特性。他非常喜歡其中一些強大的資料庫變更管理工具,但是很懷疑 DBA 是否會使用基於 XML 的語法。我向他保證,LiquiBase 還通過它的 sqlFile 和 sql 定製重構支持調用定製 SQL 腳本。

可以看到,資料庫變更日誌文件包括一個 XML 模式引用(LiquiBase 安裝中包含的 dbchangelog-1.7.xsd 文件)。我在變更日誌文件中創建了一個 <changeSet>。在 <changeSet> 中,我使用結構化的方式將變更應用到資料庫,如 LiquiBase 模式所定義。

從命令行運行 LiquiBase

定義完變更集后,可以從命令行運行 LiquiBase,如清單 2 所示:


清單 2. 從命令行運行 LiquiBase
liquibase --driver=org.apache.derby.jdbc.EmbeddedDriver \  --classpath=derby.jar \  --changeLogFile=database.changelog.xml \  --url=jdbc:derby:brewery;create=true \   --username= --password= \  update  			

在本例中,運行 LiquiBase 傳入的內容:

  • 資料庫驅動器
  • 資料庫驅動器 JAR 文件的位置所在的類路徑
  • 所創建的變更日誌文件(如 清單 1 所示)名稱為 database.changelog.xml
  • 資料庫的 URL
  • 用戶名和密碼

最後,清單 2 調用 update 命令告訴 LiquiBase 將變更應用到資料庫中。

在自動構建中運行 LiquiBase

這裡並不使用命令行選項,通過調用 LiquiBase 提供的 Ant 任務,可以將資料庫變更作為自動化構建的一部分。清單 3 展示了 Ant 任務的示例:


清單 3. 執行 updateDatabase Ant 任務的 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 中運行變更集之前的資料庫狀態:


圖 3. 運行 LiquiBase 變更集之前的資料庫狀態

圖 4 展示了運行資料庫變更集的結果,可以通過命令行(如 清單 2 所示)或從 Ant(如 清單 3 所示)運行:


圖 4. 運行 LiquiBase 變更集后將變更應用到資料庫

查看 完整的圖。

需要注意圖 4 中的幾個方面。創建了兩個特定於 LiquiBase 的表,以及一個根據 清單 1 中的變更集定義創建的新表。第一個特定於 LiquiBase 的表稱為 databasechangelog,它跟蹤應用到資料庫的所有變更 — 有助於跟蹤誰執行了資料庫變更以及原因。第二個特定於 LiquiBase-的表是 databasechangelock,標識出具有資料庫變更鎖的用戶。

還可以使用多種其他方式運行 LiquiBase,但我已經介紹了應用資料庫變更所需的大部分信息。在使用 LiquiBase 時,將花很多時間研究應用資料庫重構的各種方法,以及變更特定資料庫的複雜性。例如,LiquiBase 提供了數據回滾支持,這可能是個很大的挑戰。在展示資料庫重構示例之前,我將快速瀏覽一些資料庫集成的基本原則和實踐,它們能幫助您充分利用資料庫遷移。





頻繁集成資料庫變更

最近幾年,開發團隊將類似於處理源代碼的原則和實踐應用到資料庫資產管理中。因此,可以將資料庫變更編寫為腳本、在一個源代碼庫中共享這些資產,以及將變更集成到構建和持續集成過程,這只是自然的演進。表 1 概括了開發團隊將資料庫變更變成一個自動化過程的一部分時,需要遵循的關鍵實踐:

自動化 DBA

在我曾經參與的一些項目中,DBA 在控制開發資料庫的變更時造成了一些不必要的瓶頸。DBA 應該把時間花在一些創新的、非重複性行為,例如監視和改善資料庫性能,而不是假借控制性和一致性的名義做一些無用的重複性工作。


表 1. 資料庫集成實踐
實踐 說明
腳本化所有 DDL 和 DML 資料庫變更應該能夠從命令行運行。
數據資產的源代碼控制 使用一個版本控制庫管理所有與資料庫相關的變更。
本地資料庫沙盒 每個開發人員使用一個本地資料庫沙盒執行變更。
自動化資料庫集成 將資料庫相關的變更作為構建過程的一部分。

這些實踐確保了更好的一致性並防止變更在軟體版本轉換之間丟失。





對現有資料庫應用重構

隨著新特性添加到了應用程序中,經常需要變更資料庫的結構或修改表約束。LiquiBase 提了超過 30 種資料庫重構支持(參見 參考資料)。本節將介紹 4 種重構:添加列(Add Column)、刪除列(Drop Column)、創建表(Create Table)和操作數據。

添加列

在項目的開始,幾乎不可能考慮到資料庫中的所有列。而有時候,用戶要求新的特性 — 例如為存儲在系統中的信息收集更多的數據 — 這就要求添加新的列。清單 4 使用 LiquiBase addColumn 重構,向資料庫中的 distributor 表添加了一個列:


清單 4. 使用 LiquiBase 變更集中的 Add Column 資料庫重構
<changeSet id="4" author="joe">    <addColumn tableName="distributor">      <column name="phonenumber" type="varchar(255)"/>    </addColumn>   </changeSet>  

新的 phonenumber 列被定義為 varchar 數據類型。

刪除列

假如在以後幾個版本中,您想要刪除在清單 4 添加的 phonenumber 列。只需要調用 dropColumn 重構,如清單 5 所示:


清單 5. 刪除一個資料庫列
<dropColumn tableName="distributor" columnName="phonenumber"/>  

創建表

向資料庫添加一個新表也是常見的資料庫重構。清單 6 創建了一個新表 distributor,定義了列、約束和默認值:


清單 6. 在 LiquiBase 中創建一個新資料庫表
<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 變更集插入數據:


清單 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 表數據:


清單 8. 從 LiquiBase 變更集運行一個定製 SQL 文件
<changeSet id="6" author="joe">    <sqlFile path="insert-distributor-data.sql"/>  </changeSet>  

LiquiBase 支持很多其他資料庫重構,包括 Add Lookup Table 和 Merge Columns。可以使用如清單 4 到清單 8 所示的方式定義所有這些支持。





持續保持數據同步

在軟體開發中,如果遇到一些難題,您應該更多地關注它,而不是等到以後才手動執行這些操作,從而使問題變得更嚴重,花費也更大。資料庫遷移非常重要,自動化遷移過程能夠獲得很多好處。在本文中,我已經介紹了以下內容:

  • 演示如何使用 LiquiBase 腳本化資料庫遷移並將這些變更變成自動化構建過程的一部分
  • 描述了實現一致性的資料庫集成的原則和實踐
  • 展示如何通過使用 LiquiBase 應用資料庫重構,比如 Add Column、Create Table 和更新數據

表 2 總結了 LiquiBase 提供的一些特性的列表:


表 2. LiquiBase 部分特性總結
特性 說明
支持多個資料庫 支持 DB2、Apache Derby、MySQL、PostgreSQL、Oracle、Microsoft SQL Server、Sybase 和 HSQL 等。
查看應用到資料庫的變更的歷史。 使用 databasechangelog 表,可以查看應用到資料庫的每一個變更。
生成資料庫差異日誌 了解 LiquiBase 變更集以外的應用到資料庫的變更。
能夠運行定製 SQL 腳本 使用 LiquiBase 調用已經編寫好的 SQL 腳本。
回滾資料庫變更的工具 可以對應用到資料庫的任何變更執行回滾。

可以看到,通過自動化腳本恰當地應用變更時,資料庫遷移變得更加輕鬆,並且成為團隊中的多數成員都可以運行的重複過程。(責任編輯:A6)






[火星人 via ] 讓開發自動化: 實現自動化資料庫遷移已經有292次圍觀

http://www.coctec.com/docs/linux/show-post-69065.html