SpringBoot使用Flyway進(jìn)行數(shù)據(jù)庫(kù)遷移的實(shí)現(xiàn)示例
在本文中,我們將了解如何使用 Flyway 來(lái)管理Spring Boot應(yīng)用程序中的SQL 數(shù)據(jù)庫(kù)架構(gòu)。
Flyway是一個(gè)數(shù)據(jù)庫(kù)遷移工具,它提供遷移歷史和回滾的功能,并允許我們將應(yīng)用程序的數(shù)據(jù)庫(kù)模式相關(guān)層與數(shù)據(jù)庫(kù)實(shí)體層分離。
應(yīng)用程序設(shè)置
我們將使用的 Spring Boot 應(yīng)用程序可以使用此Spring Initializr鏈接生成。它包含所有必要的依賴項(xiàng)。
下載應(yīng)用程序并解決依賴關(guān)系后,我們將創(chuàng)建一個(gè)名為spring-boot-flyway的新 Postgres 數(shù)據(jù)庫(kù),并配置應(yīng)用程序以連接到它。
清單 2.1 application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/spring-boot-flyway spring.datasource.username=demo spring.datasource.password=demo
默認(rèn)情況下,F(xiàn)lyway 會(huì)在類路徑中的db/migration/目錄中搜索包含用于管理數(shù)據(jù)庫(kù)表和記錄的 SQL 語(yǔ)句的遷移文件。
對(duì)于舊版本的庫(kù),我們可能需要在resources/db/migration/ 中創(chuàng)建一個(gè)名為.keep的空文本文件,以確保該目錄在應(yīng)用程序啟動(dòng)期間被編譯并可用,以避免錯(cuò)誤。
完成此操作后,我們現(xiàn)在可以啟動(dòng)應(yīng)用程序并且它應(yīng)該成功運(yùn)行。
基本用法
Flyway 的工作方式是,我們?cè)?strong>resources/db/migration目錄中創(chuàng)建一個(gè)遷移文件,Spring Boot 會(huì)自動(dòng)執(zhí)行遷移腳本,因?yàn)槲覀円呀?jīng)在第 2 節(jié)中將 Flyway 依賴項(xiàng)添加到了類路徑中。
清單3.1 V1__Users.sql:
CREATE TABLE IF NOT EXISTS users ( id SERIAL, email VARCHAR(200) NOT NULL, name VARCHAR(200) NOT NULL, PRIMARY KEY (id) );
讓我們花一點(diǎn)時(shí)間來(lái)檢查一下清單 3.1 中的代碼片段。文件名V1__Users.sql遵循一定的約定:
- “ V ”表示這是版本化遷移。
- V后面的“ 1 ”是實(shí)際版本號(hào)。它也可以是“ V1_1 ”,這將轉(zhuǎn)換為版本 1.1。
- 后面是分隔符“ __ ”(兩個(gè)下劃線)。這會(huì)將版本信息與遷移文件的名稱(在本例中為Users )分開(kāi)。
- 最后一部分“ .sql ”是擴(kuò)展名;因此,該文件包含一個(gè)簡(jiǎn)單的 SQL 語(yǔ)句。
此時(shí),重新啟動(dòng)應(yīng)用程序?qū)⒃跀?shù)據(jù)庫(kù)中創(chuàng)建用戶表。此外,我們可以看到還有另一個(gè)我們沒(méi)有顯式創(chuàng)建的表 - Flyway_schema_history 。
Flyway_schema_history由 Flyway 本身用來(lái)跟蹤已應(yīng)用的遷移。如果該表丟失,F(xiàn)lyway 將假設(shè)我們是第一次初始化數(shù)據(jù)庫(kù),并按照版本號(hào)的順序運(yùn)行所有遷移。
當(dāng)Flyway_schema_history表存在時(shí),F(xiàn)lyway 將僅應(yīng)用之前未應(yīng)用過(guò)的較新的遷移文件。這意味著,為了添加新表,我們只需創(chuàng)建具有更新版本號(hào)的更新的遷移文件并重新啟動(dòng)應(yīng)用程序。
除了使用 SQL 之外,我們還可以使用Java編寫遷移腳本。在Java遷移風(fēng)格中,我們的遷移文件是Java類,必須擴(kuò)展抽象BaseJavaMigration
類并實(shí)現(xiàn)migrate
方法。
IDE 通常不希望 Java 類位于resources目錄中,因此我們將在src/main/java中創(chuàng)建一個(gè)名為db/migration的新包。非常重要的是要知道這個(gè)新包db/migration應(yīng)該位于src/main/jav目錄中。
讓我們創(chuàng)建一個(gè)新的 Java 遷移來(lái)添加新表:
清單 3.2 V2__Posts.java :
public class V2__Posts extends BaseJavaMigration { @Override public void migrate(Context context) throws Exception { var sql = """ CREATE TABLE posts ( id SERIAL, author_id INT NOT NULL, post TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ); """; try(var statement = context.getConnection().createStatement()) { statement.execute(sql); } } }
與 SQL 文件相比,使用 Java 遷移的優(yōu)點(diǎn)是我們可以添加使用普通 SQL 無(wú)法實(shí)現(xiàn)的自定義邏輯、條件和驗(yàn)證。例如,我們可以檢查另一個(gè)表是否存在或從環(huán)境中獲取某些值等。
正如您現(xiàn)在可能猜到的那樣,是的,可以在同一個(gè)代碼庫(kù)中混合 SQL 和 Java 風(fēng)格的遷移,只要我們確保兩種情況下的 Flyway 位置相同。
Flyway配置和定制
到目前為止,我們一直在使用默認(rèn)的 Flyway 行為。我們可以進(jìn)一步調(diào)整 Flyway 以滿足我們的需求。例如,我們可以更改遷移文件的默認(rèn)位置、配置數(shù)據(jù)庫(kù)架構(gòu)(也稱為表空間)、將 SQL 遷移前綴從“V”更改為我們想要的任何內(nèi)容等等。
在下面的配置中,我們配置了遷移文件所在的路徑并禁用清理數(shù)據(jù)庫(kù)(即刪除所有表)以防止在生產(chǎn)環(huán)境中意外使用。
清單4.1 application.properties:
spring.flyway.locations=classpath:migrations spring.flyway.clean-disabled=true
該鍵下還有其他可配置屬性spring.flyway
,我們可以使用它們來(lái)微調(diào)庫(kù)的行為。另外,我們可以查閱Flyway 文檔頁(yè)面以供參考。
飛行路線回調(diào)
Flyway為我們提供了配置回調(diào)的能力,這些回調(diào)可以在遷移過(guò)程的不同階段調(diào)用。回調(diào)機(jī)制是在遷移生命周期的不同階段執(zhí)行某些操作的便捷方法。
假設(shè)我們有一些默認(rèn)數(shù)據(jù)想要在應(yīng)用程序啟動(dòng)時(shí)播種。我們可以簡(jiǎn)單地創(chuàng)建一個(gè)支持該AFTER_MIGRATE
事件的回調(diào)。
清單 5.1 FlywayDatabaseSeeder.java:
public class FlywayDatabaseSeeder implements Callback { @Override public boolean supports(Event event, Context context) { return event.name().equals(Event.AFTER_MIGRATE.name()); } @Override public void handle(Event event, Context context) { try(var statement = context.getConnection().createStatement()) { var ADMIN_EMAIL = "superadmin@example.com"; var checkQuery = "SELECT id FROM users WHERE email = %s" .formatted(ADMIN_EMAIL); statement.execute(checkQuery); ResultSet resultSet = statement.getResultSet(); resultSet.last(); //return if the seeder has already been executed if(resultSet.getRow() >= 0) return; var sql = """ INSERT INTO users (email, name) VALUES ('%s', 'Super Admin') """.formatted(ADMIN_EMAIL); statement.execute(sql); } catch (SQLException e) { throw new RuntimeException(e); } } @Override public boolean canHandleInTransaction(Event event, Context context) { return true; } @Override public String getCallbackName() { return FlywayDatabaseSeeder.class.getName(); } }
在上面的清單中,在supports
方法中,我們聲明只應(yīng)針對(duì)AFTER_MIGRATE
事件執(zhí)行此回調(diào),并且在handle
方法中,我們概述了插入默認(rèn)超級(jí)管理員用戶(如果尚不存在)的邏輯。
在這之前,我們需要在 SpringBoot 中向 Flyway 注冊(cè)回調(diào)類。我們通過(guò)創(chuàng)建一個(gè)FlywayMigrationStrategy
bean 來(lái)做到這一點(diǎn)。
清單 5.2 SpringBootFlywayApplication.java :
@Bean public FlywayMigrationStrategy flywayMigrationStrategy() { return (flywayOld) -> { /* Update the existing autoconfigured Flyway bean to include our callback class */ Flyway flyway = Flyway.configure() .configuration(flywayOld.getConfiguration()) .callbacks(new FlywayDatabaseSeeder()) .load(); flyway.migrate(); }; }
rg.flywaydb.core.api.callback.Event枚舉中還有其他事件 ,我們可以配置Callback
類來(lái)支持。例如,您可以有一個(gè)回調(diào)來(lái)支持該AFTER_MIGRATE_ERROR
事件并發(fā)送 Slack 通知來(lái)提醒工程師。
技巧和竅門
在本地環(huán)境中進(jìn)行開(kāi)發(fā)時(shí),您可以從Flyway_schema_history表中刪除遷移條目。
下次啟動(dòng)應(yīng)用程序時(shí),您刪除其歷史記錄的遷移將再次執(zhí)行。這樣,您可以更正錯(cuò)誤或更新架構(gòu),同時(shí)仍在本地計(jì)算機(jī)上進(jìn)行開(kāi)發(fā),而無(wú)需刪除整個(gè)數(shù)據(jù)庫(kù)。
此外,在 SpringBoot 中,您可以控制 Flyway 在應(yīng)用程序啟動(dòng)時(shí)何時(shí)執(zhí)行遷移腳本。例如,假設(shè)我們不希望在本地環(huán)境中自動(dòng)執(zhí)行遷移。我們可以執(zhí)行以下操作:
清單6.1 SpringBootFlywayApplication.java:
@Bean public FlywayMigrationStrategy flywayMigrationStrategy(@Value("${spring.profiles.active}") String activeProfile) { return (flywayOld) -> { /* Update the existing autoconfigured Flyway bean to include our callback class */ Flyway flyway = Flyway.configure() .configuration(flywayOld.getConfiguration()) .callbacks(new FlywayDatabaseSeeder()) .load(); if(!"local".equalsIgnoreCase(activeProfile)) { flyway.migrate(); } }; }
結(jié)論
使用數(shù)據(jù)庫(kù)遷移工具的優(yōu)點(diǎn)之一是它使數(shù)據(jù)庫(kù)架構(gòu)成為應(yīng)用程序代碼庫(kù)的一部分。由于應(yīng)用程序中有一個(gè)中心參考點(diǎn),因此可以更輕松地跟蹤數(shù)據(jù)庫(kù)隨時(shí)間的變化。
到此這篇關(guān)于SpringBoot使用Flyway進(jìn)行數(shù)據(jù)庫(kù)遷移的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot Flyway數(shù)據(jù)庫(kù)遷移內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合Flyway的方法(數(shù)據(jù)庫(kù)版本遷移工具)
- Flyway詳解及Springboot集成Flyway的詳細(xì)教程
- SpringBoot整合flyway實(shí)現(xiàn)步驟解析
- SpringBoot使用flyway初始化數(shù)據(jù)庫(kù)
- SpringBoot整合flyway實(shí)現(xiàn)自動(dòng)創(chuàng)建表的方法
- SpringBoot項(xiàng)目集成Flyway詳細(xì)過(guò)程
- SpringBoot使用Flyway進(jìn)行數(shù)據(jù)庫(kù)管理的操作方法
- springboot配置flyway(入門級(jí)別教程)
- spring boot整合flyway實(shí)現(xiàn)數(shù)據(jù)的動(dòng)態(tài)維護(hù)的示例代碼
相關(guān)文章
如何在Spring Boot中實(shí)現(xiàn)異步處理與并發(fā)控制
本文我們將深入探討如何在Spring Boot中實(shí)現(xiàn)異步處理與并發(fā)控制,這一過(guò)程涉及到異步任務(wù)的執(zhí)行、線程池的配置、以及并發(fā)控制的實(shí)踐,以幫助我們提升應(yīng)用的性能和響應(yīng)能力,感興趣的朋友跟隨小編一起看看吧2024-07-07關(guān)于Cannot?resolve?com.microsoft.sqlserver:sqljdbc4:4.0報(bào)錯(cuò)問(wèn)題解
這篇文章主要給大家介紹了關(guān)于Cannot?resolve?com.microsoft.sqlserver:sqljdbc4:4.0報(bào)錯(cuò)問(wèn)題的解決辦法,這個(gè)是在pom文件中添加依賴出現(xiàn)報(bào)錯(cuò)問(wèn)題,需要的朋友可以參考下2024-02-02intelij?idea?2023創(chuàng)建java?web項(xiàng)目的完整步驟
這篇文章主要給大家介紹了關(guān)于intelij?idea?2023創(chuàng)建java?web項(xiàng)目的完整步驟,該教學(xué)主要針對(duì)各位剛剛接觸javaweb開(kāi)發(fā)的小伙伴,各位學(xué)習(xí)java的朋友也難免會(huì)經(jīng)歷這個(gè)階段,需要的朋友可以參考下2023-10-10JAVA生產(chǎn)者消費(fèi)者(線程同步)代碼學(xué)習(xí)示例
這篇文章主要介紹了JAVA線程同步的代碼學(xué)習(xí)示例,大家參考使用吧2013-11-11Spring Boot集成SpringFox 3.0與Pageable參數(shù)處理方法
這篇文章主要介紹了Spring Boot集成SpringFox 3.0與Pageable參數(shù)處理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-10-10Java使用modbus-master-tcp實(shí)現(xiàn)modbus tcp通訊
這篇文章主要為大家詳細(xì)介紹了另外一種Java語(yǔ)言的modbux tcp通訊方案,那就是modbus-master-tcp,文中的示例代碼講解詳細(xì),需要的可以了解下2023-12-12