javascript
Spring Boot 简单集成 Liquibase
Liquibase 是一個(gè)用于跟蹤、管理和應(yīng)用數(shù)據(jù)庫(kù)變化的開源的數(shù)據(jù)庫(kù)重構(gòu)工具。它將所有數(shù)據(jù)庫(kù)的變化(包括結(jié)構(gòu)和數(shù)據(jù))都保存在 changelog文件中,便于版本控制,它的目標(biāo)是提供一種數(shù)據(jù)庫(kù)類型無(wú)關(guān)的解決方案,通過執(zhí)行 schema 類型的文件來(lái)達(dá)到遷移。
Liquibase 特性
Liquibase 具備如下特性:
- 支持幾乎所有主流的數(shù)據(jù)庫(kù),如 MySQL, PostgreSQL, Oracle, Sql Server, DB2 等;
- 支持多開發(fā)者的協(xié)作維護(hù);
- 日志文件支持多種格式,如 XML, YAML, JSON, SQL等;
- 支持上下文相關(guān)邏輯
- 生成數(shù)據(jù)庫(kù)變更文檔
- 支持多種運(yùn)行方式,如命令行、Spring 集成、Maven 插件、Gradle 插件等。
更多詳情介紹,請(qǐng)查閱 Liquibase 官方文檔
Spring Boot 集成 Liquibase
添加依賴
因?yàn)?Spring Boot 已經(jīng)內(nèi)置支持整合 Liquibase,我們只需要在項(xiàng)目工程中引入 Liquibase 的依賴進(jìn)行配置即可。
<dependency><groupId>org.liquibase</groupId><artifactId>liquibase-core</artifactId><version>3.6.3</version> </dependency> 復(fù)制代碼配置 application 文件
在 classpath 中配置 application.properties 或 application.yml 文件,
# 啟用liquibase liquibase.enabled=true # 存儲(chǔ)變化的文件(changelog)位置 liquibase.change-log=classpath:sample_change.sql # 檢查存儲(chǔ)變化的文件是否存在 liquibase.check-change-log-location=true # 分環(huán)境執(zhí)行,若在 changelog 文件中設(shè)置了對(duì)應(yīng) context 屬性,則只會(huì)執(zhí)行與 dev 對(duì)應(yīng)值的 changeset liquibase.contexts=dev # 執(zhí)行前首先刪除數(shù)據(jù)庫(kù),默認(rèn) false。若設(shè)置為 true,則執(zhí)行變更前,會(huì)先刪除目標(biāo)數(shù)據(jù)庫(kù),請(qǐng)謹(jǐn)慎 liquibase.dropFirst=false # 執(zhí)行更新時(shí)將回滾 SQL 寫入的文件路徑 liquibase.rollback-file= # 如果使用工程已配置的 datasource 數(shù)據(jù)源,則以下三個(gè)數(shù)據(jù)庫(kù)連接參數(shù)可不配置 ## 訪問數(shù)據(jù)庫(kù)的連接地址 liquibase.url=jdbc:mysql://10.10.4.41:3306/test?useUnicode=true&characterEncoding=utf-8 # 訪問數(shù)據(jù)庫(kù)的用戶名 liquibase.user=test # 訪問數(shù)據(jù)庫(kù)的密碼 liquibase.password=test復(fù)制代碼注意:如果使用工程已配置的 datasource 數(shù)據(jù)源,則 liquibase.url、liquibase.user 和 liquibase.password這個(gè)三個(gè)參數(shù)可不配置,目標(biāo)數(shù)據(jù)源即為工程已配置好的數(shù)據(jù)源。因?yàn)?Spring 會(huì)自動(dòng)為 liquibase 獲取可用的數(shù)據(jù)源,詳情可查看這個(gè)類:org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration。
編寫存儲(chǔ)變更的 changelog 文件
目前 Liquibase 支持 XML、YAML、JSON 和 SQL 格式四種格式的 changelog 文件。為了方便和直觀,下面以基于 SQL 格式編寫 changelog 文件:sample_change.sql
--liquibase formatted sql--changeset zhouyi:1 -- 創(chuàng)建用戶表 CREATE TABLE `user` (`id` int(20) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL,`age` int(10) NOT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;--rollback drop table user;--changeset zhouyi:2 insert into user(id, name, age) values(1,'張三',29); insert into user(id, name, age) values(2,'李四',20); 復(fù)制代碼啟動(dòng) Spring Boot 應(yīng)用后,可以從日志看到輸出:
2019-03-27 13:13:16.439 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - DELETE FROM test.DATABASECHANGELOGLOCK 2019-03-27 13:13:16.442 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - INSERT INTO test.DATABASECHANGELOGLOCK (ID, `LOCKED`) VALUES (1, 0) 2019-03-27 13:13:16.506 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT `LOCKED` FROM test.DATABASECHANGELOGLOCK WHERE ID=1 2019-03-27 13:13:16.586 [main] [] INFO liquibase.lockservice.StandardLockService.info:42 - Successfully acquired change log lock 2019-03-27 13:13:16.697 [main] [] INFO liquibase.changelog.StandardChangeLogHistoryService.info:42 - Creating database history table with name: test.DATABASECHANGELOG 2019-03-27 13:13:16.700 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - CREATE TABLE test.DATABASECHANGELOG (ID VARCHAR(255) NOT NULL, AUTHOR VARCHAR(255) NOT NULL, FILENAME VARCHAR(255) NOT NULL, DATEEXECUTED datetime NOT NULL, ORDEREXECUTED INT NOT NULL, EXECTYPE VARCHAR(10) NOT NULL, MD5SUM VARCHAR(35) NULL, `DESCRIPTION` VARCHAR(255) NULL, COMMENTS VARCHAR(255) NULL, TAG VARCHAR(255) NULL, LIQUIBASE VARCHAR(20) NULL, CONTEXTS VARCHAR(255) NULL, LABELS VARCHAR(255) NULL, DEPLOYMENT_ID VARCHAR(10) NULL) 2019-03-27 13:13:17.570 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT COUNT(*) FROM test.DATABASECHANGELOG 2019-03-27 13:13:17.575 [main] [] INFO liquibase.changelog.StandardChangeLogHistoryService.info:42 - Reading from test.DATABASECHANGELOG 2019-03-27 13:13:17.579 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT * FROM test.DATABASECHANGELOG ORDER BY DATEEXECUTED ASC, ORDEREXECUTED ASC 2019-03-27 13:13:17.585 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT COUNT(*) FROM test.DATABASECHANGELOGLOCK 2019-03-27 13:13:17.678 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - CREATE TABLE `user` (`id` int(20) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL,`age` int(10) NOT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 2019-03-27 13:13:17.935 [main] [] INFO liquibase.changelog.ChangeSet.info:42 - Custom SQL executed 2019-03-27 13:13:17.937 [main] [] INFO liquibase.changelog.ChangeSet.info:42 - ChangeSet classpath:sample_change.sql::1::zhouyi ran successfully in 297ms 2019-03-27 13:13:17.938 [main] [] INFO liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT MAX(ORDEREXECUTED) FROM test.DATABASECHANGELOG復(fù)制代碼從數(shù)據(jù)庫(kù)中可以看到變化,首次運(yùn)行新增了 3 張表,
其中DATABASECHANGELOG 和 DATABASECHANGELOGLOCK 表是 Liquibase 自動(dòng)生成的,而 user 表是執(zhí)行我們編寫的 changeset變更集后生成的,并且也已經(jīng)執(zhí)行了第 2 個(gè)變更集,插入了兩條數(shù)據(jù)。
SQL 格式的 changelogs 文件
SQL 格式的 changelog 文件使用 SQL 注釋作為元數(shù)據(jù),為確保這個(gè)文件被 Liquibase 識(shí)別為 changelog文件,,SQL 文件必須以以下注釋開頭:
--liquibase formatted sql 復(fù)制代碼changeset 變更
SQL 格式的 changelog 文件中在變更的 SQL 前需要加上以下注釋,表示為一個(gè) changeset變更集:
--changeset author:id attribute1:value1 attribute2:value2 [...] 復(fù)制代碼在之前的 sample_change.sql 文件中編寫了兩條 changeset (變更集),
變更集 changeset 是通過 author + id 的方式來(lái)保證唯一性,如以上 zhouyi:1 和 zhouyi:2 兩條表更集。
變更集提供以下屬性:
| stripComments | 設(shè)置為 true 可在執(zhí)行之前刪除 SQL 中的任何注釋, 否則為 false。如果未設(shè)置, 則默認(rèn)值為 true |
| splitStatements | |
| endDelimiter | 應(yīng)用于語(yǔ)句結(jié)尾的分隔符。默認(rèn)為“;”,也可以設(shè)置為“” |
| runAlways | 在每次運(yùn)行時(shí)執(zhí)行變更集, 即使之前已運(yùn)行 |
| runOnChange | 在首次看到更改并每次更改變更集時(shí)執(zhí)行更改 |
| context | 如果在運(yùn)行時(shí)傳遞了特定上下文, 則執(zhí)行更改。任何字符串都可以用于上下文名稱, 并且大小寫不敏感。 |
| logicalFilePath | 用于在創(chuàng)建變更集的唯一標(biāo)識(shí)符時(shí)重寫文件名和路徑。移動(dòng)或重命名更改日志時(shí)所必需。 |
| labels | 標(biāo)簽是對(duì)變更集進(jìn)行分類的通用方法集類似上下文, 但工作方式正好相反。如果不是在運(yùn)行時(shí)定義一組上下文, 然后在變更集中定義一個(gè)匹配表達(dá)式, 而是在上下文中定義一組標(biāo)簽, 在運(yùn)行時(shí)定義一個(gè)匹配表達(dá)式。 |
| runInTransaction | 變更集是否應(yīng)作為單個(gè)事務(wù)運(yùn)行 (如果可能),默認(rèn)值為 true。請(qǐng)注意此屬性,如果設(shè)置為 false, 并且通過運(yùn)行包含多個(gè)語(yǔ)句的變更集部分發(fā)生錯(cuò)誤, 則 liquibase 數(shù)據(jù)庫(kù)的 databasechangeloglock 表將處于無(wú)效狀態(tài) |
| failOnError | 如果在執(zhí)行變更集時(shí)發(fā)生錯(cuò)誤, 遷移是否應(yīng)返回失敗 |
| dbms | 要用于該變更集的數(shù)據(jù)庫(kù)的類型。當(dāng)遷移步驟運(yùn)行時(shí), 它將根據(jù)此屬性檢查數(shù)據(jù)庫(kù)類型,如:oracle、mysql |
| logicalFilePath | 在數(shù)據(jù)庫(kù) databasechangeloglock 中設(shè)置邏輯文件路徑, 而不是在執(zhí)行 liquibase 的 sql 物理文件位置。 |
前置條件
可以為每個(gè)變更集指定先決條件。目前, 僅支持 SQL 檢查前置條件。
--preconditions onFail:HALT onError:HALT --precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM my_table 復(fù)制代碼回滾操作
變更集可能包括回滾變更集時(shí)要應(yīng)用的語(yǔ)句。回滾聲明也是使用表注釋。
--rollback SQL STATEMENT 復(fù)制代碼例如在前面編寫的 changelog 文件中的第一個(gè) changeset:
--changeset zhouyi:1 -- 創(chuàng)建用戶表 CREATE TABLE `user` (`id` int(20) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL,`age` int(10) NOT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;--rollback drop table user; 復(fù)制代碼首先的變更的 SQL 含義是新建一個(gè) user 表,回滾的 SQL 則表示刪除新建的 user 表。
Liquibase 最佳實(shí)踐
下面介紹可應(yīng)用于項(xiàng)目的一些最佳實(shí)踐。
一個(gè)變更集只設(shè)置一次更改
盡可能地避免對(duì)一個(gè)變更集進(jìn)行多次更改,以避免自動(dòng)提交 SQL 語(yǔ)句而可能使數(shù)據(jù)庫(kù)處于非預(yù)期狀態(tài)。 如 --changeset zhouyi:1 變更集,只新建一張 user 表,后面不再修改該變更集,如果需要變更,可以新增一條變更集。
變更集的 ID
選擇適合您的方法。有的人是使用從 1 開始的序列號(hào), 并且在更改日志中是唯一的,也有些人選擇一個(gè)描述性的名稱(例如:new-address-table)
總是考慮回滾
盡量嘗試以可以回滾的方式編寫變更集,如 --changeset zhouyi:1 變更集新建一個(gè) user 表,在后面跟上回滾的 SQL, --rollback drop table user;
為變更集添加注釋
盡量為每一個(gè)變更集條目增加注釋,如 -- 創(chuàng)建用戶表
開發(fā)人員使用流程
- 使用您最喜歡的 IDE 或編輯器, 創(chuàng)建一個(gè)包含更改的新本地更改集;
- 運(yùn)行 Liquibase 以執(zhí)行新的變更集 (這將測(cè)試 SQL 代碼);
- 在應(yīng)用程序代碼中執(zhí)行相應(yīng)的更改 (例如, Java 代碼);
- 測(cè)試驗(yàn)證新的應(yīng)用程序代碼以及數(shù)據(jù)庫(kù)更改;
- 提交變更集和應(yīng)用程序代碼。
總結(jié)
以上是生活随笔為你收集整理的Spring Boot 简单集成 Liquibase的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基本数据与引用数据类型参数传递
- 下一篇: JavaScript字符串转数字的5种方