初始化 DataSource

org.springframework.jdbc.datasource.init 包提供了初始化現有 DataSource 的支援。嵌入式資料庫支援為應用程式建立和初始化 DataSource 提供了一個選項。但是,有時您可能需要初始化在某個伺服器上執行的例項。

使用 Spring XML 初始化資料庫

如果您想初始化資料庫並能提供對 DataSource bean 的引用,您可以在 spring-jdbc 名稱空間中使用 initialize-database 標籤。

<jdbc:initialize-database data-source="dataSource">
	<jdbc:script location="classpath:com/foo/sql/db-schema.sql"/>
	<jdbc:script location="classpath:com/foo/sql/db-test-data.sql"/>
</jdbc:initialize-database>

前面的示例針對資料庫運行了兩個指定的指令碼。第一個指令碼建立模式,第二個指令碼用測試資料集填充表。指令碼位置也可以是帶有萬用字元的模式,採用 Spring 中資源常用的 Ant 樣式(例如,classpath*:/com/foo/**/sql/*-data.sql)。如果您使用模式,指令碼將按照其 URL 或檔名的字典順序執行。

資料庫初始化器的預設行為是無條件地執行提供的指令碼。這可能不總是您想要的,例如,如果您針對已包含測試資料的資料庫執行指令碼。透過遵循常見的模式(如前面所示,先建立表然後插入資料)可以減少意外刪除資料的可能性。如果表已存在,第一步將失敗。

但是,為了更好地控制現有資料的建立和刪除,XML 名稱空間提供了一些額外的選項。第一個是切換初始化開啟和關閉的標誌。您可以根據環境設定此標誌(例如,從系統屬性或環境 bean 中獲取布林值)。以下示例從系統屬性中獲取值:

<jdbc:initialize-database data-source="dataSource"
	enabled="#{systemProperties.INITIALIZE_DATABASE}"> (1)
	<jdbc:script location="..."/>
</jdbc:initialize-database>
1 從名為 INITIALIZE_DATABASE 的系統屬性中獲取 enabled 的值。

控制現有資料處理方式的第二個選項是更容忍失敗。為此,您可以控制初始化器忽略它從指令碼執行的 SQL 中的某些錯誤的能力,如下例所示:

<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
	<jdbc:script location="..."/>
</jdbc:initialize-database>

在前面的示例中,我們表示我們期望有時指令碼會針對空資料庫執行,並且指令碼中存在一些 DROP 語句,因此這些語句會失敗。所以失敗的 SQL DROP 語句將被忽略,但其他失敗將導致異常。如果您的 SQL 方言不支援 DROP …​ IF EXISTS(或類似)但您想在重新建立所有測試資料之前無條件地刪除它們,這將非常有用。在這種情況下,第一個指令碼通常是一組 DROP 語句,後跟一組 CREATE 語句。

ignore-failures 選項可以設定為 NONE(預設值)、DROPS(忽略失敗的刪除)或 ALL(忽略所有失敗)。

每個語句應由 ; 或換行符分隔,如果指令碼中根本沒有 ; 字元。您可以全域性控制或逐個指令碼控制,如下例所示:

<jdbc:initialize-database data-source="dataSource" separator="@@"> (1)
	<jdbc:script location="classpath:com/myapp/sql/db-schema.sql" separator=";"/> (2)
	<jdbc:script location="classpath:com/myapp/sql/db-test-data-1.sql"/>
	<jdbc:script location="classpath:com/myapp/sql/db-test-data-2.sql"/>
</jdbc:initialize-database>
1 將分隔符指令碼設定為 @@
2 db-schema.sql 的分隔符設定為 ;

在此示例中,兩個 test-data 指令碼使用 @@ 作為語句分隔符,而只有 db-schema.sql 使用 ;。此配置指定預設分隔符為 @@,並針對 db-schema 指令碼覆蓋此預設值。

如果您需要比 XML 名稱空間提供的更多控制,可以直接使用 DataSourceInitializer 並將其定義為應用程式中的元件。

依賴於資料庫的其他元件的初始化

一大類應用程式(在 Spring 上下文啟動後才使用資料庫的應用程式)可以毫無問題地使用資料庫初始化器。如果您的應用程式不屬於此類,您可能需要閱讀本節的其餘部分。

資料庫初始化器依賴於 DataSource 例項,並在其初始化回撥中執行提供的指令碼(類似於 XML bean 定義中的 init-method、元件中的 @PostConstruct 方法或實現 InitializingBean 的元件中的 afterPropertiesSet() 方法)。如果其他 bean 依賴於相同的資料庫並在初始化回撥中使用該資料庫,則可能會出現問題,因為資料尚未初始化。一個常見的例子是快取,它急切地初始化並在應用程式啟動時從資料庫載入資料。

為了解決這個問題,您有兩個選擇:將您的快取初始化策略更改為稍後階段,或確保資料庫初始化器首先初始化。

如果應用程式在您的控制之下,則更改快取初始化策略可能很容易,否則則不然。實現此目的的一些建議包括:

  • 讓快取在首次使用時延遲初始化,這可以提高應用程式啟動時間。

  • 讓您的快取或初始化快取的單獨元件實現 LifecycleSmartLifecycle。當應用程式上下文啟動時,您可以透過設定 SmartLifecycleautoStartup 標誌來自動啟動它,並且您可以透過呼叫封閉上下文的 ConfigurableApplicationContext.start() 來手動啟動 Lifecycle

  • 使用 Spring ApplicationEvent 或類似的自定義觀察者機制來觸發快取初始化。ContextRefreshedEvent 始終由上下文在準備好使用時釋出(所有 bean 都已初始化之後),因此它通常是一個有用的鉤子(這是 SmartLifecycle 預設的工作方式)。

確保資料庫初始化器首先初始化也可能很容易。實現此目的的一些建議包括:

  • 依賴 Spring BeanFactory 的預設行為,即 bean 按照註冊順序初始化。您可以透過採用 XML 配置中一組 <import/> 元素的常見做法來輕鬆安排此操作,這些元素對應用程式模組進行排序,並確保資料庫和資料庫初始化首先列出。

  • DataSource 和使用它的業務元件分開,並透過將它們放在單獨的 ApplicationContext 例項中來控制它們的啟動順序(例如,父上下文包含 DataSource,子上下文包含業務元件)。這種結構在 Spring Web 應用程式中很常見,但可以更普遍地應用。

© . This site is unofficial and not affiliated with VMware.