Spring Boot使用Liquibase最佳實踐


 

Liquibase問題

 

隨着項目的發展,一個項目中的代碼量會非常龐大,同時數據庫表也會錯綜復雜。如果一個項目使用了Liquibase對數據庫結構進行管理,越來越多的問題會浮現出來。

 

  1. ChangeSet文件同時多人在修改,自己的ChangeSet被改掉,甚至被刪除掉。
  2. 開發人員將ChangeSet添加到已經執行過的文件中,導致執行順序出問題。
  3. 開發人員擅自添加對業務數據的修改,其它環境無法執行並報錯。
  4. ChangeSet中SQL包含schema名稱,導致其它環境schema名稱變化時,ChangeSet報錯。
  5. 開發人員不小心改動了已經執行過的ChangeSet,在啟動時會報錯。

 

Liquibase基本規范

 

  1. ChangeSet id使用[任務ID]-[日期]-[序號],如 T100-20181009-001
  2. ChangeSet必須填寫author
  3. Liquibase禁止對業務數據進行sql操作
  4. 使用<sql>時,禁止包含schema名稱
  5. Liquibase禁止使用存儲過程
  6. 所有表,列要加remarks進行注釋
  7. 已經執行過的ChangeSet嚴禁修改。
  8. 不要隨便升級項目liquibase版本,特別是大版本升級。不同版本ChangeSet MD5SUM的算法不一樣。

 

其它數據庫規范不再贅述。

 

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
    <changeSet id="T100-20181009-001" author="markfredchen" >
        <createTable tableName="demo_user" remarks="用戶表">
            <column name="id" type="bigint" remarks="用戶ID,主鍵">
                <constraints nullable="false" primaryKey="true" primaryKeyName="pk_demo_user_id"/>
            </column>
            <column name="username" type="varchar(100)" remarks="用戶名">
                <constraints nullable="false"/>
            </column>
            ...
        </createTable>
    </changeSet>
</databaseChangeLog>

 

 

有效文件管理

 

使用Liquibase中提供<include file="xxx"/>tag,可以將ChangeSet分布在不同文件中。同時<include/>支持多級引用。
基於此功能可以對項目中的ChangeSet進行有效管理。推薦使用以下規范進行管理。

 

根據發布進行管理

 

  1. 每個發布新建一個文件夾,所有發布相關的ChangeSet文件以及數據初始化文件,均放在些文件夾中。
  2. 每個發布新建一個master.xml。此master.xml中,include本次發布需要執行的ChangeSet文件
  3. 根據開發小組獨立ChangeSet文件(可選)
  4. 根據功能獨立ChangeSet文件。例如user.xml, company.xml

 

resources
  |-liquibase |-user | |- master.xml | |- release.1.0.0 | | |- release.xml | | |- user.xml -- 用戶相關表ChangeSet | | |- user.csv -- 用戶初始化數據 | | |- company.xml -- 公司相關表ChangeSet | |- release.1.1.0 | | |- release.xml | | |- ...

 

模塊化管理

 

當項目變得龐大之后,一個服務可能包含的功能模塊會越來越多。此時大家會想盡辦法進行模塊拆分,逐步進行微服務化。然而在面對錯綜復雜的Liquibase ChangeSet就會無從下手。
針對這種將來可能會面對的問題,項目初期就對Liquibase進行模塊化管理,將在未來帶來很大收益。
首先說明一下Spring Boot中Liquibase默認是如何執行以及執行結果。

 

  1. 在啟動時,LiquibaseAutoConfiguration會根據默認配置初始化SpringLiquibase
  2. SpringLiquibase.afterPropertiesSet()中執行ChangeSet文件
  3. 第一次跑ChangeSets的時候,會在數據庫中自動創建兩個表databasechangelogdatabasechangeloglock

 

因此我們可以認為一個SpringLiquibase執行為一個模塊。

 

引入多模塊管理時,基於上節文件管理規范,我們基於模塊管理再做下調整。

 

resources
  |-liquibase |-user | |- master.xml | |- release.1.0.0 | | |- release.xml | | |- user.xml -- 用戶相關表ChangeSet | | |- user.csv -- 用戶初始化數據 | | |- company.xml -- 公司相關表ChangeSet | |- release.1.1.0 | | |- release.xml | | |- ... |- order | |- master.xml | |- release.1.0.0 | | |- ...

 

當有一天我們需要把訂單模塊拆分成獨立服務時,我們只需要將模塊相關的ChangeSet文件遷出來。即可完成數據結構的拆分。

 

那如何在一個Spring Boot運行多個SpringLiquibase呢?需要對代碼進行以下調整。

 

  1. 禁用Spring Boot自動運行Liquibase。

 

當以下配置被啟用時,Spring Boot AutoConfigure會使用默認配置初始化名為springLiquibase的Bean。然后我們不對其進行配置,Spring Boot啟動時會報錯。

 

# application.properties # spring boot 2以上 spring.liquibase.enabled=false # spring boot 2以下 liquibase.enabled=false
  1. Spring Boot配置Liquibase Bean

配置兩個SpringLiquibase Bean,Bean名稱分別為userLiquibase和orderLiqubase。

@Configuration
public class LiquibaseConfiguration() {

    /**
     *  用戶模塊Liquibase   
     */
    @Bean
    public SpringLiquibase userLiquibase(DataSource dataSource) {
        SpringLiquibase liquibase = new SpringLiquibase();
        // 用戶模塊Liquibase文件路徑
        liquibase.setChangeLog("classpath:liquibase/user/master.xml");
        liquibase.setDataSource(dataSource);
        liquibase.setShouldRun(true);
        liquibase.setResourceLoader(new DefaultResourceLoader());
        // 覆蓋Liquibase changelog表名
        liquibase.setDatabaseChangeLogTable("user_changelog_table");
        liquibase.setDatabaseChangeLogLockTable("user_changelog_lock_table");
        return liquibase;
    }
    /**
     *  訂單模塊Liquibase   
     */
    @Bean
    public SpringLiquibase orderLiquibase() {
      SpringLiquibase liquibase = new SpringLiquibase();
      liquibase.setChangeLog("classpath:liquibase/order/master.xml");
      liquibase.setDataSource(dataSource);
      liquibase.setShouldRun(true);
      liquibase.setResourceLoader(new DefaultResourceLoader());
      liquibase.setDatabaseChangeLogTable("order_changelog_table");
      liquibase.setDatabaseChangeLogLockTable("order_changelog_lock_table");
      return liquibase;
    }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM