資料庫初始化
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 logger 來輸出結構描述建立。如果您啟用除錯模式,這會自動為您完成。 |
此外,如果 Hibernate 從頭開始建立結構描述(也就是說,如果 ddl-auto
屬性設定為 create
或 create-drop
),則在啟動時會執行類別路徑根目錄中名為 import.sql
的檔案。如果您很小心,這對於示範和測試可能很有用,但在生產環境中,您可能不希望它存在於類別路徑中。這是 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 模組新增至您的類別路徑。org.flywaydb:flyway-core
支援記憶體和基於檔案的資料庫。否則,需要資料庫特定的模組。例如,PostgreSQL 請使用 org.flywaydb:flyway-database-postgresql
,MySQL 請使用 org.flywaydb:flyway-mysql
。請參閱 Flyway 文件 以取得更多詳細資訊。
通常,遷移是 V<VERSION>__<NAME>.sql
格式的腳本(其中 <VERSION>
是底線分隔的版本,例如 ‘1’ 或 ‘2_1’)。預設情況下,它們位於名為 classpath:db/migration
的目錄中,但您可以透過設定 spring.flyway.locations
來修改該位置。這是一個以逗號分隔的一個或多個 classpath:
或 filesystem:
位置的清單。例如,以下組態將在預設類別路徑位置和 /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
來排序。實作已棄用的 FlywayCallback
介面的 Bean 也可以被偵測到,但是它們不能與 Callback
bean 一起使用。
預設情況下,Flyway 會自動裝配您內容中的 (@Primary
) DataSource
,並將其用於遷移。如果您想使用不同的 DataSource
,您可以建立一個並將其 @Bean
標記為 @FlywayDataSource
。如果您這樣做並且想要兩個資料來源,請記住建立另一個資料來源並將其標記為 @Primary
。或者,您可以使用 Flyway 的原生 DataSource
,方法是在外部屬性中設定 spring.flyway.[url,user,password]
。設定 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
新增至您的類別路徑。
當您將 |
預設情況下,主要變更記錄檔是從 db/changelog/db.changelog-master.yaml
讀取,但您可以透過設定 spring.liquibase.change-log
來變更位置。除了 YAML 之外,Liquibase 也支援 JSON、XML 和 SQL 變更記錄檔格式。
預設情況下,Liquibase 會自動裝配您內容中的 (@Primary
) DataSource
,並將其用於遷移。如果您需要使用不同的 DataSource
,您可以建立一個並將其 @Bean
標記為 @LiquibaseDataSource
。如果您這樣做並且想要兩個資料來源,請記住建立另一個資料來源並將其標記為 @Primary
。或者,您可以使用 Liquibase 的原生 DataSource
,方法是在外部屬性中設定 spring.liquibase.[driver-class-name,url,user,password]
。設定 spring.liquibase.url
或 spring.liquibase.user
中的任何一個都足以讓 Liquibase 使用其自己的 DataSource
。如果這三個屬性中的任何一個尚未設定,則將使用其等效的 spring.datasource
屬性的值。
請參閱 LiquibaseProperties
以取得有關可用設定的詳細資訊,例如內容、預設結構描述和其他設定。
將 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
設定指定它在所有生產變更集執行後執行。您現在可以使用例如 insert 變更集 來插入資料,或使用 sql 變更集 來直接執行 SQL。
最後要做的是組態 Spring Boot 在執行測試時啟動 test
設定檔。若要執行此操作,您可以將 @ActiveProfiles("test")
註解新增至您的 @SpringBootTest
註解測試類別。
依賴已初始化的資料庫
資料庫初始化是在應用程式啟動時作為應用程式內容重新整理的一部分執行的。為了允許在啟動期間存取已初始化的資料庫,會自動偵測充當資料庫初始化程式的 bean 和需要已初始化資料庫的 bean。其初始化依賴於資料庫已初始化的 bean 被組態為依賴於那些初始化它的 bean。如果在啟動期間,您的應用程式嘗試存取資料庫且尚未初始化,您可以組態對初始化資料庫和需要已初始化資料庫的 bean 進行額外偵測。
偵測資料庫初始化程式
Spring Boot 將自動偵測以下類型的 bean,這些 bean 初始化 SQL 資料庫
-
DataSourceScriptDatabaseInitializer
-
EntityManagerFactory
-
Flyway
-
FlywayMigrationInitializer
-
R2dbcScriptDatabaseInitializer
-
SpringLiquibase
如果您正在使用第三方啟動器來進行資料庫初始化程式庫,它可能會提供偵測器,以便也自動偵測其他類型的 bean。若要讓其他 bean 被偵測到,請在 META-INF/spring.factories
中註冊 DatabaseInitializerDetector
的實作。
偵測依賴資料庫初始化的 Bean
Spring Boot 將自動偵測以下類型的 bean,這些 bean 依賴於資料庫初始化
-
AbstractEntityManagerFactoryBean
(除非spring.jpa.defer-datasource-initialization
設定為true
) -
DSLContext
(jOOQ) -
EntityManagerFactory
(除非spring.jpa.defer-datasource-initialization
設定為true
) -
JdbcClient
-
JdbcOperations
-
NamedParameterJdbcOperations
如果您正在使用第三方啟動器資料存取程式庫,它可能會提供偵測器,以便也自動偵測其他類型的 bean。若要讓其他 bean 被偵測到,請在 META-INF/spring.factories
中註冊 DependsOnDatabaseInitializationDetector
的實作。或者,使用 @DependsOnDatabaseInitialization
註解 bean 的類別或其 @Bean
方法。