資料庫初始化
SQL 資料庫的初始化方式因技術棧而異。當然,如果資料庫是獨立程序,您也可以手動進行初始化。建議使用單一機制進行模式生成。
使用 Hibernate 初始化資料庫
您可以設定 spring.jpa.hibernate.ddl-auto 來控制 Hibernate 的資料庫初始化。支援的值包括 none、validate、update、create 和 create-drop。Spring Boot 會根據您是否使用嵌入式資料庫為您選擇一個預設值。嵌入式資料庫透過檢查 Connection 型別和 JDBC URL 來識別。hsqldb、h2 或 derby 是嵌入式資料庫,其他則不是。如果識別出嵌入式資料庫且未檢測到模式管理器(Flyway 或 Liquibase),則 ddl-auto 預設為 create-drop。在所有其他情況下,它預設為 none。
從記憶體資料庫切換到“真實”資料庫時,請務必小心,不要假定新平臺中表和資料的存在。您必須顯式設定 ddl-auto 或使用其他機制來初始化資料庫。
您可以透過啟用 org.hibernate.SQL 記錄器來輸出模式建立。如果您啟用除錯模式,此操作會自動為您完成。 |
此外,如果 Hibernate 從頭開始建立模式(即,如果 ddl-auto 屬性設定為 create 或 create-drop),則在啟動時會執行 classpath 根目錄中名為 import.sql 的檔案。這對於演示和測試非常有用,但您在生產環境中可能不希望它在 classpath 中。這是一個 Hibernate 功能(與 Spring 無關)。
使用基本 SQL 指令碼初始化資料庫
Spring Boot 可以自動建立您的 JDBC DataSource 或 R2DBC ConnectionFactory 的模式(DDL 指令碼)並初始化其資料(DML 指令碼)。
預設情況下,它從 optional:classpath*:schema.sql 載入模式指令碼,並從 optional:classpath*:data.sql 載入資料指令碼。這些模式和資料指令碼的位置可以分別使用 spring.sql.init.schema-locations 和 spring.sql.init.data-locations 進行自定義。optional: 字首表示即使檔案不存在,應用程式也會啟動。要讓應用程式在檔案不存在時啟動失敗,請刪除 optional: 字首。
此外,Spring Boot 會處理 optional:classpath*:schema-${platform}.sql 和 optional:classpath*:data-${platform}.sql 檔案(如果存在),其中 ${platform} 是 spring.sql.init.platform 的值。這允許您在必要時切換到特定於資料庫的指令碼。例如,您可以選擇將其設定為資料庫的供應商名稱(hsqldb、h2、oracle、mysql、postgresql 等)。
預設情況下,SQL 資料庫初始化僅在使用嵌入式記憶體資料庫時執行。要始終初始化 SQL 資料庫,無論其型別如何,請將 spring.sql.init.mode 設定為 always。同樣,要停用初始化,請將 spring.sql.init.mode 設定為 never。預設情況下,Spring Boot 啟用其基於指令碼的資料庫初始化器的快速失敗功能。這意味著如果指令碼導致異常,應用程式將啟動失敗。您可以透過設定 spring.sql.init.continue-on-error 來調整此行為。
預設情況下,基於指令碼的 DataSource 初始化在建立任何 JPA EntityManagerFactory bean 之前執行。schema.sql 可用於為 JPA 管理的實體建立模式,data.sql 可用於填充資料。雖然我們不建議使用多種資料來源初始化技術,但如果您希望基於指令碼的 DataSource 初始化能夠基於 Hibernate 執行的模式建立,請將 spring.jpa.defer-datasource-initialization 設定為 true。這將推遲資料來源初始化,直到任何 EntityManagerFactory bean 已建立並初始化。然後,schema.sql 可用於對 Hibernate 執行的任何模式建立進行補充,data.sql 可用於填充資料。
初始化指令碼支援 -- 用於單行註釋,/* */ 用於塊註釋。不支援其他註釋格式。 |
如果您正在使用 更高級別的資料庫遷移工具,例如 Flyway 或 Liquibase,您應該單獨使用它們來建立和初始化模式。不建議將基本的 schema.sql 和 data.sql 指令碼與 Flyway 或 Liquibase 一起使用,並且在將來的版本中將移除此支援。
初始化 Spring Batch 資料庫
如果您使用 Spring Batch,它預先打包了適用於大多數流行資料庫平臺的 SQL 初始化指令碼。Spring Boot 可以檢測您的資料庫型別並在啟動時執行這些指令碼。如果您使用嵌入式資料庫,這預設會發生。您也可以為任何資料庫型別啟用它,如以下示例所示
-
屬性
-
YAML
spring.batch.jdbc.initialize-schema=always
spring:
batch:
jdbc:
initialize-schema: "always"
您也可以透過將 spring.batch.jdbc.initialize-schema 設定為 never 來顯式關閉初始化。
使用更高級別的資料庫遷移工具
在啟動時執行 Flyway 資料庫遷移
要在啟動時自動執行 Flyway 資料庫遷移,請將相應的 Flyway 模組新增到您的 classpath。記憶體資料庫和基於檔案的資料庫支援 org.flywaydb:flyway-core。否則,需要一個特定於資料庫的模組。例如,將 org.flywaydb:flyway-database-postgresql 與 PostgreSQL 一起使用,將 org.flywaydb:flyway-mysql 與 MySQL 一起使用。有關更多詳細資訊,請參閱 Flyway 文件。
通常,遷移是格式為 V<VERSION>__<NAME>.sql 的指令碼(其中 <VERSION> 是一個以下劃線分隔的版本,例如 '1' 或 '2_1')。預設情況下,它們位於名為 classpath:db/migration 的目錄中,但您可以透過設定 spring.flyway.locations 來修改該位置。這是一個逗號分隔的一個或多個 classpath: 或 filesystem: 位置列表。例如,以下配置將在預設 classpath 位置和 /opt/migration 目錄中搜索指令碼
-
屬性
-
YAML
spring.flyway.locations=classpath:db/migration,filesystem:/opt/migration
spring:
flyway:
locations: "classpath:db/migration,filesystem:/opt/migration"
您還可以新增一個特殊的 {vendor} 佔位符以使用特定於供應商的指令碼。假設以下
-
屬性
-
YAML
spring.flyway.locations=classpath:db/migration/{vendor}
spring:
flyway:
locations: "classpath:db/migration/{vendor}"
前面的配置不使用 db/migration,而是根據資料庫型別(例如 MySQL 的 db/migration/mysql)設定要使用的目錄。DatabaseDriver 中提供了受支援的資料庫列表。
遷移也可以用 Java 編寫。Flyway 將自動配置任何實現 JavaMigration 的 bean。
FlywayProperties 提供了 Flyway 的大部分設定以及一小部分可用於停用遷移或關閉位置檢查的附加屬性。如果您需要對配置進行更多控制,請考慮註冊一個實現 FlywayConfigurationCustomizer 的 bean。
Spring Boot 呼叫 Flyway.migrate() 執行資料庫遷移。如果您需要更多控制,請提供一個實現 FlywayMigrationStrategy 的 @Bean。
Flyway 支援 SQL 和 Java 回撥。要使用基於 SQL 的回撥,請將回調指令碼放在 classpath:db/migration 目錄中。要使用基於 Java 的回撥,請建立一個或多個實現 Callback 的 bean。任何此類 bean 都會自動註冊到 Flyway。它們可以透過使用 @Order 或實現 Ordered 進行排序。
預設情況下,Flyway 會自動裝配您上下文中的(@Primary)DataSource 並將其用於遷移。如果您希望使用不同的 DataSource,您可以建立一個並將其 @Bean 標記為 @FlywayDataSource。如果您這樣做並且需要兩個資料來源(例如保留主要自動配置的 DataSource),請記住將 @Bean 註解的 defaultCandidate 屬性設定為 false。或者,您可以透過在外部屬性中設定 spring.flyway.[url,user,password] 來使用 Flyway 的原生 DataSource。設定 spring.flyway.url 或 spring.flyway.user 中的任何一個都足以使 Flyway 使用自己的 DataSource。如果這三個屬性中的任何一個未設定,將使用其對應的 spring.datasource 屬性的值。
您還可以使用 Flyway 為特定場景提供資料。例如,您可以將測試特定的遷移放在 src/test/resources 中,並且它們僅在您的應用程式啟動進行測試時執行。此外,您可以使用特定於配置檔案的配置來自定義 spring.flyway.locations,以便某些遷移僅在特定配置檔案處於活動狀態時執行。例如,在 application-dev.properties 中,您可以指定以下設定
-
屬性
-
YAML
spring.flyway.locations=classpath:/db/migration,classpath:/dev/db/migration
spring:
flyway:
locations: "classpath:/db/migration,classpath:/dev/db/migration"
透過此設定,dev/db/migration 中的遷移僅在 dev 配置檔案處於活動狀態時執行。
在啟動時執行 Liquibase 資料庫遷移
要在啟動時自動執行 Liquibase 資料庫遷移,請將 org.liquibase:liquibase-core 新增到您的 classpath。
|
當您將 |
預設情況下,主變更日誌從 db/changelog/db.changelog-master.yaml 讀取,但您可以透過設定 spring.liquibase.change-log 來更改位置。除了 YAML,Liquibase 還支援 JSON、XML 和 SQL 變更日誌格式。
預設情況下,Liquibase 會自動裝配您上下文中的(@Primary)DataSource 並將其用於遷移。如果您希望使用不同的 DataSource,您可以建立一個並將其 @Bean 標記為 @LiquibaseDataSource。如果您這樣做並且需要兩個資料來源(例如保留主要自動配置的 DataSource),請記住將 @Bean 註解的 defaultCandidate 屬性設定為 false。或者,您可以透過在外部屬性中設定 spring.liquibase.[driver-class-name,url,user,password] 來使用 Liquibase 的原生 DataSource。設定 spring.liquibase.url 或 spring.liquibase.user 中的任何一個都足以使 Liquibase 使用自己的 DataSource。如果這三個屬性中的任何一個未設定,將使用其對應的 spring.datasource 屬性的值。
有關可用設定(例如上下文、預設模式等)的詳細資訊,請參閱 LiquibaseProperties。
如果您想在使用 Liquibase 例項之前對其進行自定義,您還可以使用 Customizer<Liquibase> bean。
將 Flyway 用於僅測試遷移
如果您想建立 Flyway 遷移來填充您的測試資料庫,請將它們放在 src/test/resources/db/migration 中。例如,一個名為 src/test/resources/db/migration/V9999__test-data.sql 的檔案將在您的生產遷移之後執行,並且僅在您執行測試時執行。您可以使用此檔案建立所需的測試資料。此檔案不會打包在您的 uber jar 或容器中。
將 Liquibase 用於僅測試遷移
如果您想建立 Liquibase 遷移來填充您的測試資料庫,您必須建立一個測試變更日誌,其中也包含生產變更日誌。
首先,您需要配置 Liquibase 在執行測試時使用不同的變更日誌。一種方法是建立一個 Spring Boot test 配置檔案並將 Liquibase 屬性放在其中。為此,請建立一個名為 src/test/resources/application-test.properties 的檔案,並在其中放置以下屬性
-
屬性
-
YAML
spring.liquibase.change-log=classpath:/db/changelog/db.changelog-test.yaml
spring:
liquibase:
change-log: "classpath:/db/changelog/db.changelog-test.yaml"
這將配置 Liquibase 在 test 配置檔案中執行時使用不同的變更日誌。
現在在 src/test/resources/db/changelog/db.changelog-test.yaml 建立變更日誌檔案
databaseChangeLog:
- include:
file: classpath:/db/changelog/db.changelog-master.yaml
- changeSet:
runOrder: "last"
id: "test"
changes:
# Insert your changes here
此變更日誌將在執行測試時使用,並且不會打包在您的 uber jar 或容器中。它包含生產變更日誌,然後宣告一個新的變更集,其 runOrder: last 設定指定它在所有生產變更集執行後執行。您現在可以使用例如 插入變更集 插入資料或 sql 變更集 直接執行 SQL。
最後一步是配置 Spring Boot 以在執行測試時啟用 test 配置檔案。為此,您可以將 @ActiveProfiles("test") 註解新增到您的 @SpringBootTest 註解的測試類中。
依賴已初始化的資料庫
資料庫初始化在應用程式啟動時作為應用程式上下文重新整理的一部分執行。為了允許在啟動期間訪問已初始化的資料庫,會自動檢測充當資料庫初始化器的 bean 和需要資料庫已初始化的 bean。其初始化依賴於資料庫已初始化的 bean 被配置為依賴於初始化它的 bean。如果在啟動期間,您的應用程式嘗試訪問資料庫且尚未初始化,您可以配置對初始化資料庫並需要資料庫已初始化的 bean 的額外檢測。
檢測資料庫初始化器
Spring Boot 將自動檢測以下初始化 SQL 資料庫的 bean 型別
如果您正在使用第三方資料庫初始化庫的 starter,它可能會提供一個檢測器,以便其他型別的 bean 也能自動檢測到。要檢測其他 bean,請在 META-INF/spring.factories 中註冊 DatabaseInitializerDetector 的實現。
檢測依賴資料庫初始化的 Bean
Spring Boot 將自動檢測以下依賴資料庫初始化的 bean 型別
-
AbstractEntityManagerFactoryBean(除非spring.jpa.defer-datasource-initialization設定為true) -
DSLContext(jOOQ) -
EntityManagerFactory(除非spring.jpa.defer-datasource-initialization設定為true)
如果您正在使用第三方資料訪問庫的 starter,它可能會提供一個檢測器,以便其他型別的 bean 也能自動檢測到。要檢測其他 bean,請在 META-INF/spring.factories 中註冊 DependsOnDatabaseInitializationDetector 的實現。或者,使用 @DependsOnDatabaseInitialization 註解 bean 的類或其 @Bean 方法。