使用 Liquibase 管理資料庫版本 - SpringBoot 2.7 .2 實戰基礎

来源:https://www.cnblogs.com/youyacoder/archive/2022/08/10/16572856.html
-Advertisement-
Play Games

Liquibase 具有執行鎖,已經執行過的內容不會重覆執行。在執行 changeSet 時,由於改動的內容可以通過 Liquibase 提供的標簽編寫,所以無關具體的資料庫產品(MySQL、Oracle 等),Liquibase 底層會根據實際使用的資料庫類型轉化為對應的 SQL。 ...


優雅哥 SpringBoot 2.7 .2 實戰基礎 - 05 -使用 Liquibase 管理資料庫版本

在企業開發中,資料庫版本管理好像是一個偽命題,大多項目都是通過 Power Designer 之類的工具建模、生成 SQL 語句,然後去資料庫中執行。在開發過程中如果遇到修改表結構,再補充修改表結構的語句,大家依次去執行,在本地及各個環境中同步表結構。但這種模式,在我參與過的項目中或多或少都出現過問題:忘記同步表結構,導致在服務啟動或運行時出錯。

1 Liquibase 介紹

SpringBoot 官方文檔中推薦了兩款工具來管理資料庫版本:FlywayLiquibase。前者我沒有在項目中使用過,所以本文就只討論 Liquibase。

使用 Liquibase 需要定義一堆 XML 文件,這些 XML 稱為 changelog 文件。每個 changelog 文件中又包含多個變化集合 changeSet,每個 changeSet 記錄了作者、改變的內容。changeSet 中要修改的內容,通過 createTableaddColumn 等標簽進行操作。通過這種 XML 文件的方式,就可以將代碼版本與資料庫版本關聯在一起。項目啟動,會自動執行 changelog XML 文件。Liquibase 具有執行鎖,已經執行過的內容不會重覆執行。在執行 changeSet 時,由於改動的內容可以通過 Liquibase 提供的標簽編寫,所以無關具體的資料庫產品(MySQL、Oracle 等),Liquibase 底層會根據實際使用的資料庫類型轉化為對應的 SQL。

通過上面的描述,可以看出 Liquibase 帶來的幾個好處:

  1. 支持多類型的資料庫產品,無需維護 SQL 腳本;
  2. 項目啟動可以自動升級資料庫;
  3. 代碼版本與資料庫版本關聯在一起。

2 在老項目中使用 Liquibase

在咱們的 demo hero-springboot-demo 中,之前已經手動通過 SQL 語句創建了資料庫表 computer,現在想通過 Liquibase 來管理資料庫版本和維護表結構,該怎麼辦呢?本節就通過這個案例來說明已存在的老項目中如何引用 Liquibase。

2.1 配置 Maven 插件

Liquibase 提供了 Maven 插件,使用該插件可以根據資料庫逆向生成 changlog 文件。在 pom.xml 的 plugins 下添加 Liquibase 插件:

<plugin>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-maven-plugin</artifactId>
    <version>4.9.1</version>
    <configuration>
        <propertyFileWillOverride>true</propertyFileWillOverride>
        <outputChangeLogFile>temp/temp-changelog.xml</outputChangeLogFile>
        <driver>com.mysql.cj.jdbc.Driver</driver>
        <url>jdbc:mysql://127.0.0.1:3306/hero_springboot_demo?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true</url>
        <username>root</username>
        <password>Mysql.123</password>
        <outputFileEncoding>UTF-8</outputFileEncoding>
        <verbose>true</verbose>
        <diffTypes>tables, views, columns, indexs,foreignkeys, primarykeys, uniqueconstraints, data</diffTypes>
    </configuration>
</plugin>

上面配置 Liquibase 的 Maven 插件:資料庫連接信息和Liquibase生成規則配置。生成的文件路徑為 temp 目錄下的 temp-changelog.xml,Liquibase 不會自動生成文件夾,需要手動在項目根目錄下創建 temp 目錄。

2.2 逆向生成 changelog

在控制台執行 mvn liquibase:generateChangeLog 或者在界面上執行 generateChangeLog:

image-20220801160733941

執行後查看 temp/temp-changelog.xml 文件:

image-20220801163132937

生成的這個文件就是 changelog 文件,該文件中包括兩個 changeSet:第一個是創建表結構;第二個初始化數據。

在第一個 changeSet 的 createTable 中,對 id 欄位配置了自增屬性 autoIncrement:

<column autoIncrement="true" name="id" type="BIGINT">
    <constraints nullable="false" primaryKey="true"/>
</column>

不知道為啥,我這不生效。要使該欄位自增,要用 addAutoIncrement 標簽。第一個 changeSet 需要添加上該標簽,添加後如下:

<changeSet id="T100-20220801-yyg-001" author="yyg">
    <createTable remarks="電腦" tableName="computer">
        <column autoIncrement="true" name="id" type="BIGINT">
            <constraints nullable="false" primaryKey="true"/>
        </column>
        <column name="size" remarks="尺寸" type="DECIMAL(4, 1)"/>
        <column name="operation" remarks="操作系統" type="VARCHAR(32)"/>
        <column name="year" remarks="年份" type="VARCHAR(4)"/>
    </createTable>
    <addAutoIncrement tableName="computer" columnName="id" columnDataType="BIGINT"/>
</changeSet>

獲取到歷史表結構及數據的 changelog 文件後,接下來的步驟與 SpringBoot 整合 Liquibase 一致。

3 在 SpringBoot 中使用 Liquibase

3.1 添加依賴

pom.xml 文件中添加 liquibase 依賴 liquibase-core,該依賴版本號在 spring-boot-dependencies中已定義,直接添加依賴即可。

<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
</dependency>

3.2 添加 changelog

src/main/resources 創建目錄 dbdb 目錄用來存放 Liquibase 相關的 changelog 文件。

db 目錄下還可以按模塊創建其他目錄,由於我們這裡只有一個 computer 類,屬於 demo 演示,故就在 db 目錄下創建子目錄 demodb/demo/ 目錄就存放 demo 演示的所有 changelog 配置文件。將前面 Liquibase 逆向生成的 temp-changelog.xml 文件移動到 db/demo/ 目錄下,並重命名為 demo-changelog-v1.xml

db 目錄下創建 changelog-master.xml 文件,該文件為主配置文件,作用就是引入所有模塊的 changelog 文件:

<?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
                        https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">

    <includeAll path="demo" relativeToChangelogFile="true"/>
</databaseChangeLog>

除了根節點,裡面就一句話,表示將當前路徑下 demo 目錄中的 changelog 文件都引入。假設 db 目錄下還有其他模塊(目錄),繼續通過 <includeAll> 元素引入即可。

src/main/resources 中文件目錄結構如下:

src/main/resources/
|- db/
	|- demo/
		|- demo-changelog-v1.xml
	|- changelog-master.xml

3.3 changeSet

回過頭來看 demo-changelog-v1.xml 文件,裡面的內容是之前生成的,前面講過包括兩個 changeSetchangeSet 用來定義對資料庫的表更操作,包括:

表結構的操作:創建表、刪除表、修改表結構(添加列、刪除列等)

表數據的操作:表中數據的增刪改查

視圖的操作、索引的操作等

幾乎只要是對資料庫的操作,都可以寫在 changeSet 中。當服務啟動的時候,會自動執行主配置文件中包含的所有 changeSet。需要特別註意:changeSet 一經執行,就不能修改!! 雖然 changeSet 元素有一個屬性 runOnChange ,非常不建議亂用。如果要修改 changeSet裡面的內容怎麼辦呢?重新寫一個 changeSet,在裡面編寫要修改的內容。例如在第一個 changeSet 中使用 <createTable> 創建表,表中有一個列名為 field,在該 changeSet 執行後(成功啟動過服務),想將該列列名 field 修改為 f,這時候不能直接修改第一個 changeSet,而是要寫第二個 changeSet,通過 <renameColumn> 來修改列名,然後重啟服務。

changeSet元素有兩個必填的屬性 authoridauthor 表示作者,當前的是誰定義的這個changeSet,就填誰的名字,這樣便於追溯。 id 要求唯一,我在項目開發中,id一般按照這個規則:[任務ID]-[日期]-[作者]-[序號],如 T100-20220801-yyg-001

通常小版本更新(如欄位級別的變更),就在同一個文件中追加新的 changeSet 即可。一個 changelog 文件可以包括多個 changeSet,每個 changeSet 中可以包括多個語句,如多個 createTable、insert 等。

大版本更新,就重新編寫 changeLog 文件,如 demo-changelog-v2.xml

按照上面所講,我們修改一下 demo-changelog-v1.xml 中的兩個 changeSet 的 id 和 author:

<?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
                    https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
    <!--
    1. id使用[任務ID]-[日期]-[作者]-[序號],如 T100-20220801-yyg-001
    2. 必須填寫author
    3. 所有 表、列 必須加remarks進行註釋
    4. 已經執行過的ChangeSet嚴禁修改
    -->
    <changeSet id="T100-20220801-yyg-001" author="yyg">
        <createTable remarks="電腦" tableName="computer">
				...
				</createTable>
    </changeSet>
    <changeSet id="T100-20220801-yyg-002" author="yyg">
        ...
    </changeSet>
</databaseChangeLog>

3.4 添加配置

在 application.yml 中添加 liquibase 的配置:

spring:
  liquibase:
    enabled: true
    drop-first: false
    change-log: classpath:/db/changelog-master.xml

上述配置開啟 liquibase,並指定主文件的路徑。

3.5 啟動服務測試

現在啟動服務,會發現服務啟動失敗,而且控制台會出現如下提示:

Reason: liquibase.exception.DatabaseException: Table 'computer' already exists

此時需要刪除資料庫中的表,然後重新啟動服務。

服務啟動成功後,會自動創建兩張 liquibase 相關的表:DATABASECHANGELOGDATABASECHANGELOGLOCK表。

現在嘗試在 demo-changelog-v1.xml中編寫第三個 changeSet:

<changeSet id="T100-20220801-yyg-003" author="yyg">
    <addColumn tableName="computer">
        <column name="color" type="VARCHAR(8)" defaultValue="red" remarks="顏色"/>
    </addColumn>
</changeSet>

這個 changeSet 為 computer 表新增列 color,預設值為 red。重啟服務,服務啟動後查看 computer 表:

  1. 已新增列 color
  2. color 預設值已設置為 red

image-20220801225227371

這樣便成功在 SpringBoot 中使用 liquibase。

4 常見問題

4.1 Waiting for changelog lock

如果啟動服務時,控制台提示如下信息:

Liquibase - Waiting for changelog lock
Waiting for changelog lock....

通常是由於 Liquibase 在重構資料庫時使資料庫死鎖。解決方法如下:

1 查看鎖住資料庫的id:

SELECT * FROM DATABASECHANGELOGLOCK where LOCKED = true;

2 解鎖:

UPDATE DATABASECHANGELOGLOCK
SET locked=0, lockgranted=null, lockedby=null
WHERE id={id}

{id} 為第一步中查詢出來對應記錄的id。

4.2 主鍵自增無效

前面已經談到,需要配置 addAutoIncrement 標簽

<addAutoIncrement tableName="xxx" columnName="xx" columnDataType="BIGINT"/>

4.3 預設值無效

與主鍵自增無效類似,為 column 設置預設值 defaultValuedefaultValueNumeric也無效。

設置預設值需要使用標簽 addDefaultValue

<addDefaultValue tableName="xxx" columnName="xx" defaultValueNumeric="0"/>

Liquibase 還有很多強大的功能,就留給大家在使用過程中一步一步探索吧。

image

今日程式員優雅哥(/ youyacoder;[email protected])學習到此結束~~~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 面向對象編程(高級) 筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 類變數和類方法(static) 類變數 類變數-提出問題 提出問題的主要目的就是讓大家思考解決之道,從而引出我要講的知識點.說:有一群小孩在玩堆雪人,不時有新的小 ...
  • Java常用類(一) 一、String 類:(不可變的字元序列) 1.1 String:字元串,使用一對 " " 引起來表示。 String 類聲明為 final 的,不可被繼承。 String 類實現了 Serializable 介面:表示字元串是支持序列化的。實現了 Comparable 介面: ...
  • 哈嘍兄弟們,又是新的一天!今天你敲代碼了嗎? 一、序言 為什麼要挑戰自己在代碼里不寫 for loop?因為這樣可以迫使你去學習使用比較高級、比較地道的語法或 library。文中以 python 為例子,講了不少大家其實在別人的代碼里都見過、但自己很少用的語法。 自從我開始探索 Python 中驚 ...
  • (防扒小助手) 本人CSDN博客: https://blog.csdn.net/m0_61753302 本人博客園博客(同步CSDN): 何以牽塵 - 博客園 (cnblogs.com)https://www.cnblogs.com/kalesky/ 如果對你有用的話歡迎點贊關註喲! ​​​​​​​ ...
  • 一、前言 ReentrantLock 是基於 AQS 實現的同步框架,關於 AQS 的源碼在 這篇文章 已經講解過,ReentrantLock 的主要實現都依賴AQS,因此在閱讀本文前應該先瞭解 AQS 機制。本文並不關註 ReentrantLock 如何使用,只敘述其具體實現。 二、Reentra ...
  • Java集合01 1.什麼是集合? 前面我們保存數據使用的是數組,數組有不足的地方,我們來分析一下: 長度開始時必須指定,而且一但指定不能更改 保存的必須是同一類型的元素 使用數組進行增加/刪除元素的很麻煩 重新創建一個數組,將舊數組的元素拷貝過來 集合的好處: 可以動態地保存任意多個對象,使用比較 ...
  • 在生產環境中,對發在的API增加授權保護是非常必要的。JWT作為一個無狀態的授權校撿技術,非常適合於分散式系統架構。伺服器端不需要保存用戶狀態,因此,無須採用Redis等技術來實現各個服務節點之間共用Session數據。 本節通過實例講解如何用JWT技術進行授權認證和保護。 1.1 配置安全類 (1 ...
  • Tabby Tabby 是一名老外在 Github 開源的終端連接的工具,至今已經累積 20K+ star。 Tabby 的功能特性大概有: 支持多平臺,Windows、MacOS(Intel 晶元/M1 晶元)、Linux 都有對應的安裝包的; 自帶 SFTP 功能,能夠與 Linux 系統傳輸文 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...