嵌入式資料庫支援
建立嵌入式資料庫
您可以將嵌入式資料庫實例公開為 Bean,如下列範例所示
-
Java
-
Kotlin
-
Xml
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.H2)
.addScripts("schema.sql", "test-data.sql")
.build();
}
@Bean
fun dataSource() = EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.H2)
.addScripts("schema.sql", "test-data.sql")
.build()
<jdbc:embedded-database id="dataSource" generate-name="true" type="H2">
<jdbc:script location="classpath:schema.sql"/>
<jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>
先前的組態建立了一個嵌入式 H2 資料庫,該資料庫使用來自類別路徑根目錄下的 schema.sql
和 test-data.sql
資源的 SQL 進行填充。此外,作為最佳實務,嵌入式資料庫被分配了一個唯一產生的名稱。嵌入式資料庫作為 javax.sql.DataSource
類型的 Bean 提供給 Spring 容器,然後可以根據需要注入到資料存取物件中。
有關所有支援選項的更多詳細資訊,請參閱 EmbeddedDatabaseBuilder
的 javadoc。
選擇嵌入式資料庫類型
本節介紹如何選擇 Spring 支援的三種嵌入式資料庫之一。它包括以下主題
使用 HSQL
Spring 支援 HSQL 1.8.0 及更高版本。如果未明確指定類型,HSQL 是預設的嵌入式資料庫。若要明確指定 HSQL,請將 embedded-database
標籤的 type
屬性設定為 HSQL
。如果您使用 Builder API,請使用 EmbeddedDatabaseType.HSQL
呼叫 setType(EmbeddedDatabaseType)
方法。
自訂嵌入式資料庫類型
雖然每種支援的類型都帶有預設的連線設定,但在必要時可以自訂它們。以下範例使用 H2 和自訂驅動程式
-
Java
-
Kotlin
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setDatabaseConfigurer(EmbeddedDatabaseConfigurers
.customizeConfigurer(H2, this::customize))
.addScript("schema.sql")
.build();
}
private EmbeddedDatabaseConfigurer customize(EmbeddedDatabaseConfigurer defaultConfigurer) {
return new EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
@Override
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
super.configureConnectionProperties(properties, databaseName);
properties.setDriverClass(CustomDriver.class);
}
};
}
}
@Configuration
class DataSourceConfig {
@Bean
fun dataSource(): DataSource {
return EmbeddedDatabaseBuilder()
.setDatabaseConfigurer(EmbeddedDatabaseConfigurers
.customizeConfigurer(EmbeddedDatabaseType.H2) { this.customize(it) })
.addScript("schema.sql")
.build()
}
private fun customize(defaultConfigurer: EmbeddedDatabaseConfigurer): EmbeddedDatabaseConfigurer {
return object : EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
override fun configureConnectionProperties(
properties: ConnectionProperties,
databaseName: String
) {
super.configureConnectionProperties(properties, databaseName)
properties.setDriverClass(CustomDriver::class.java)
}
}
}
}
使用嵌入式資料庫測試資料存取邏輯
嵌入式資料庫提供了一種輕量級的方式來測試資料存取程式碼。下一個範例是一個資料存取整合測試範本,它使用嵌入式資料庫。當嵌入式資料庫不需要在測試類別之間重複使用時,使用此類範本可能對於一次性使用很有用。但是,如果您希望建立在測試套件中共享的嵌入式資料庫,請考慮使用 Spring TestContext Framework 並在 Spring ApplicationContext
中將嵌入式資料庫組態為 Bean,如 建立嵌入式資料庫 中所述。以下列表顯示了測試範本
-
Java
-
Kotlin
public class DataAccessIntegrationTestTemplate {
private EmbeddedDatabase db;
@BeforeEach
public void setUp() {
// creates an HSQL in-memory database populated from default scripts
// classpath:schema.sql and classpath:data.sql
db = new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.addDefaultScripts()
.build();
}
@Test
public void testDataAccess() {
JdbcTemplate template = new JdbcTemplate(db);
template.query( /* ... */ );
}
@AfterEach
public void tearDown() {
db.shutdown();
}
}
class DataAccessIntegrationTestTemplate {
private lateinit var db: EmbeddedDatabase
@BeforeEach
fun setUp() {
// creates an HSQL in-memory database populated from default scripts
// classpath:schema.sql and classpath:data.sql
db = EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.addDefaultScripts()
.build()
}
@Test
fun testDataAccess() {
val template = JdbcTemplate(db)
template.query( /* ... */)
}
@AfterEach
fun tearDown() {
db.shutdown()
}
}
為嵌入式資料庫產生唯一名稱
如果開發團隊的測試套件無意中嘗試重新建立相同資料庫的其他實例,則嵌入式資料庫經常會遇到錯誤。如果 XML 組態檔或 @Configuration
類別負責建立嵌入式資料庫,並且對應的組態隨後在同一個測試套件(即在同一個 JVM 程序中)內的多個測試案例中重複使用時,就很容易發生這種情況 — 例如,針對嵌入式資料庫的整合測試,其 ApplicationContext
組態僅在啟用的 Bean 定義 Profile 方面有所不同。
這些錯誤的根本原因是 Spring 的 EmbeddedDatabaseFactory
(<jdbc:embedded-database>
XML Namespace 元素和 Java 組態的 EmbeddedDatabaseBuilder
內部都使用它)在未另行指定的情況下,將嵌入式資料庫的名稱設定為 testdb
。對於 <jdbc:embedded-database>
的情況,嵌入式資料庫通常被分配一個等於 Bean 的 id
的名稱(通常是類似 dataSource
的名稱)。因此,後續嘗試建立嵌入式資料庫不會產生新的資料庫。相反,相同的 JDBC 連線 URL 會被重複使用,並且建立新嵌入式資料庫的嘗試實際上指向從相同組態建立的現有嵌入式資料庫。
為了解決這個常見問題,Spring Framework 4.2 提供了對為嵌入式資料庫產生唯一名稱的支援。若要啟用產生名稱的使用,請使用以下選項之一。
-
EmbeddedDatabaseFactory.setGenerateUniqueDatabaseName()
-
EmbeddedDatabaseBuilder.generateUniqueName()
-
<jdbc:embedded-database generate-name="true" … >
擴充嵌入式資料庫支援
您可以透過兩種方式擴充 Spring JDBC 嵌入式資料庫支援
-
實作
EmbeddedDatabaseConfigurer
以支援新的嵌入式資料庫類型。 -
實作
DataSourceFactory
以支援新的DataSource
實作,例如連線池以管理嵌入式資料庫連線。
我們鼓勵您在 GitHub Issues 上為 Spring 社群貢獻擴充功能。