Liquibase 中的先決條件
1. 概述
Liquibase 是一個強大的資料庫管理工具,提供了一種追蹤和部署資料庫變更的簡單方法。它還允許透過我們所謂的元資料來描述變更集在部署時的行為。
先決條件是一種元資料形式,通常用於控制變更日誌或單一變更集的執行。它們確保在繼續部署之前滿足某些要求。
在本教程中,我們將探索先決條件並學習定義條件邏輯和錯誤處理,以優化部署期間的變更集控制。
2. 了解先決條件
先決條件是 Liquibase 的一個基本特性。它們讓我們定義在應用變更集或變更之前必須滿足的特定條件。因此,我們可以將先決條件視為資料庫變更的守護者。
在部署變更集之前,Liquibase 會系統性地評估這些條件。如果條件不滿足,Liquibase 將阻止執行變更集。根據先決條件行為,它可以引發失敗或警告,或跳過變更集。此機制確保僅當資料庫狀態符合所需標準時才會套用變更。透過這種方式,我們可以確保嚴格控制部署,同時最大限度地降低問題或錯誤的風險。
讓我們探討一下 Liquibase 先決條件可能有用的幾個實際場景:
- 我們可以將變更限制為特定資料庫類型、一組資料庫類型甚至特定版本,以確保相容性。
- 我們可以在建立或修改資料庫中的物件之前檢查它是否已經存在,從而避免意外錯誤。
- 在執行不可逆的變更之前檢查現有資料也是有意義的。例如,如果表仍然包含數據,我們可以阻止刪除表(
dropTable
)。 - 最後,我們可以在進行任何更改之前驗證特定資料的存在或不存在。例如,如果遷移涉及在配置表中插入新行,我們可以確保該行不存在,以避免重複或不一致。
這些做法有助於我們確保部署的安全性並更好地預測潛在問題。
3. 定義先決條件語法
先決條件是我們直接新增到變更日誌檔案中以控制變更的執行的標籤。讓我們來談談它們的語法。
3.1.先決條件的基本語法
讓我們從一個簡單的例子開始:
<preConditions>
<dbms type="mysql,oracle" />
</preConditions>
這裡我們使用dbms
前提條件。這可確保資料庫是 MySQL 或 Oracle。
Liquibase 提供了幾個符合我們需求的先決條件標籤。以下是一些先決條件的範例:
-
dbms
檢查資料庫類型 -
runningAs
驗證資料庫使用者名稱 -
tableExists
檢查表是否存在 -
columnExists
確保特定列的存在 -
foreignKeyExists
檢查外鍵是否存在 -
sqlCheck
執行 SQL 查詢並與預期結果進行比較
我們可以在各種變更日誌檔案格式(例如 XML、YAML 或 JSON)中定義這些先決條件。在 Liquibase 4.27.0 之前,只有sqlCheck
與格式化的 SQL 相容。**從4.27.0 版本開始,其他先決條件(如tableExists
和viewExists
也支援SQL 變更日誌**:
--precondition-table-exists table:users
對於喜歡使用 SQL 更改日誌的使用者來說,這是一個有價值的改進。
我們可以隨時參考官方文件來取得可用先決條件及其屬性的完整清單。
3.2.嵌套先決條件
Liquibase 讓我們可以靈活地使用<and>
、 <or>
和<not>
等邏輯標籤嵌套或包裝多個先決條件。這使得創建更複雜的條件成為可能。
讓我們來看一個例子:
<preConditions>
<or>
<and>
<dbms type="oracle" />
<runningAs username="baeldung" />
</and>
<and>
<dbms type="mysql" />
<runningAs username="baeldung" />
</and>
</or>
</preConditions>
在此範例中,我們檢查資料庫是否為 Oracle,且資料庫使用者是否為baeldung
,或資料庫是否為 MySQL,且使用者是否相同。
如果未指定邏輯運算符,Liquibase 預設套用AND
邏輯。我們再舉一個例子:
<preConditions>
<tableExists tableName="users"/>
<columnExists tableName="users" columnName="email"/>
</preConditions>
在這種情況下,必須滿足兩個條件: users
表必須存在並且必須包含email
列。
Liquibase 對先決條件使用惰性求值。這意味著如果<and>
中的第一個條件失敗,則不會檢查下一個條件。類似地,如果<or>
中的第一個條件失敗,它會跳過其餘的條件。
4. 全局與局部前提條件
我們可以在兩個層面使用先決條件:在變更日誌中全域使用,以及在每個變更集中本機使用。
全域或變更日誌先決條件在變更日誌的頂部定義,先於任何變更集。它們適用於所有變更集,並且可用於常規檢查,例如確保資料庫相容:
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<preConditions>
<dbms type="mysql"/>
<runningAs username="baeldung"/>
<sqlCheck expectedResult="9.1.0">
SELECT @@version;
</sqlCheck>
</preConditions>
<changeSet id="BAEL-1000" author="baeldung">
<addColumn tableName="users">
<column name="country" type="varchar(25)"/>
</addColumn>
</changeSet>
<changeSet id="BAEL-1001" author="baeldung">
<addColumn tableName="tutorials">
<column name="code" type="varchar(5)"/>
</addColumn>
</changeSet>
</databaseChangeLog>
在此範例中,我們檢查資料庫是 MySQL,並且部署變更集的資料庫使用者是baeldung
。我們也使用sqlCheck
檢查了資料庫版本是否為 9.1.0。因此,如果任何一項條件不滿足,就不會執行任何變更集。
另一方面,局部先決條件是在變更集的頂部定義的,並且僅適用於該特定的變更集。它們支援有針對性的檢查,例如確保在應用變更之前表或列存在。
讓我們舉個例子:
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="BAEL-1000" author="baeldung">
<addColumn tableName="users">
<column name="country" type="varchar(25)"/>
</addColumn>
</changeSet>
<changeSet id="BAEL-1002" author="baeldung">
<preConditions>
<tableExists tableName="users"/>
<columnExists tableName="users" columnName="last_visit"/>
</preConditions>
<dropColumn tableName="users" columnName="last_visit"/>
</changeSet>
</databaseChangeLog>
此先決條件僅適用於id
為BAEL-1002
變更集。它確保users
表和last_visit
列存在,然後才允許刪除該列。
5. 處理先決條件失敗和錯誤
Liquibase 區分先決條件失敗和執行過程中的錯誤:
- 當先決條件成功運行但未滿足預期標準時,就會發生失敗。
- 當技術問題(例如語法錯誤)阻止先決條件執行時,就會發生錯誤。
我們使用onFail
和onError
屬性來指定如何處理先決條件檢查期間的失敗或錯誤。
5.1. onFail
和onError
屬性
讓我們來看一個包含先決條件的變更集的變更日誌範例:
<changeSet id="BAEL-1003" author="baeldung">
<preConditions onFail="HALT" onError="HALT">
<not>
<columnExists tableName="users" columnName="verified"/>
</not>
</preConditions>
<addColumn tableName="users">
<column name="verified" type="boolean" defaultValue="false"/>
</addColumn>
</changeSet>
我們可以使用mvn liquibase:update
命令來執行此更改日誌。
如果verified
列已存在,則前提條件失敗並顯示以下訊息:
Not precondition failed
例如,如果users
表不存在,則會發生錯誤:
liquibase.exception.DatabaseException: Table 'baeldung_liquibase.users' doesn't exist
在這兩種情況下,當發生故障或錯誤時, HALT
值都會立即停止執行。
5.2. onFail
和onError
屬性的值
我們可以配置不同的行為來處理先決條件:
-
HALT
立即停止變更日誌的執行。這是預設行為。 -
WARN
記錄警告但繼續執行 -
MARK_RAN
在DATABASECHANGELOG表中將 changeSet 標記為已執行,並繼續 -
CONTINUE
跳過 changeSet 並繼續執行
下表總結了可能的值:
onFail 屬性值 |
onError 屬性值 |
|
---|---|---|
全域前提條件 | 暫停,警告 | 暫停,警告 |
本地前提條件 | 暫停、繼續、標記運行、警告 | 暫停、繼續、標記運行、警告 |
附加屬性(例如onErrorMessage
和onFailMessage
)可以啟用自訂錯誤或失敗訊息:
<preConditions onFail="WARN" onFailMessage="Column verified already exists">
<not>
<columnExists tableName="users" columnName="verified"/>
</not>
</preConditions>
這些屬性在處理先決條件時具有靈活性並提供自訂行為。
6. 結論
在本文中,我們探討了Liquibase 先決條件如何在資料庫更新期間提高控制和精確度。它們確保資料庫在應用變更之前滿足特定條件。這種方法可以降低風險並避免潛在的錯誤。
透過有效利用先決條件,我們可以簡化部署並維護資料庫完整性。
與往常一樣,原始碼可在 GitHub 上取得。 與往常一樣,原始碼可在 GitHub 上取得。