控制資料庫連線
使用 DataSource
Spring 透過 DataSource
取得資料庫連線。DataSource
是 JDBC 規範的一部分,並且是一個通用的連線工廠。它讓容器或框架可以對應用程式碼隱藏連線池和交易管理問題。作為開發人員,您不需要知道如何連線到資料庫的詳細資訊。那是管理員的責任,由他們設定資料來源。在您開發和測試程式碼時,您很可能同時扮演這兩種角色,但您不一定需要知道生產資料來源是如何配置的。
當您使用 Spring 的 JDBC 層時,您可以從 JNDI 取得資料來源,或者您可以使用第三方提供的連線池實作來配置您自己的資料來源。傳統的選擇是 Apache Commons DBCP 和 C3P0,它們都提供 Bean 樣式的 DataSource
類別;對於現代的 JDBC 連線池,請考慮使用 HikariCP 及其建構器樣式的 API。
您應該僅為了測試目的而使用 DriverManagerDataSource 和 SimpleDriverDataSource 類別(包含在 Spring 發行版中)!這些變體不提供池化功能,並且在多次請求連線時效能不佳。 |
以下章節使用 Spring 的 DriverManagerDataSource
實作。稍後將介紹其他幾種 DataSource
變體。
配置 DriverManagerDataSource
的方法
-
使用
DriverManagerDataSource
取得連線,就像您通常取得 JDBC 連線一樣。 -
指定 JDBC 驅動程式的完整類別名稱,以便
DriverManager
可以載入驅動程式類別。 -
提供在 JDBC 驅動程式之間有所不同的 URL。(請參閱您的驅動程式文件以取得正確的值。)
-
提供使用者名稱和密碼以連線到資料庫。
以下範例顯示如何配置 DriverManagerDataSource
-
Java
-
Kotlin
-
Xml
@Bean
DriverManagerDataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://127.0.0.1:");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean
fun dataSource() = DriverManagerDataSource().apply {
setDriverClassName("org.hsqldb.jdbcDriver")
url = "jdbc:hsqldb:hsql://127.0.0.1:"
username = "sa"
password = ""
}
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
接下來的兩個範例顯示 DBCP 和 C3P0 的基本連線能力和組態。若要了解有助於控制池化功能的更多選項,請參閱各個連線池實作的產品文件。
以下範例顯示 DBCP 組態
-
Java
-
Kotlin
-
Xml
@Bean(destroyMethod = "close")
BasicDataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://127.0.0.1:");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean(destroyMethod = "close")
fun dataSource() = BasicDataSource().apply {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:hsql://127.0.0.1:"
username = "sa"
password = ""
}
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
以下範例顯示 C3P0 組態
-
Java
-
Kotlin
-
Xml
@Bean(destroyMethod = "close")
ComboPooledDataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("org.hsqldb.jdbcDriver");
dataSource.setJdbcUrl("jdbc:hsqldb:hsql://127.0.0.1:");
dataSource.setUser("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean(destroyMethod = "close")
fun dataSource() = ComboPooledDataSource().apply {
driverClass = "org.hsqldb.jdbcDriver"
jdbcUrl = "jdbc:hsqldb:hsql://127.0.0.1:"
user = "sa"
password = ""
}
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
使用 DataSourceUtils
DataSourceUtils
類別是一個方便且功能強大的輔助類別,它提供 static
方法以從 JNDI 取得連線,並在必要時關閉連線。它支援具有 DataSourceTransactionManager
以及 JtaTransactionManager
和 JpaTransactionManager
的線程綁定 JDBC Connection
。
請注意,JdbcTemplate
隱含 DataSourceUtils
連線存取,在每個 JDBC 操作背後使用它,隱含地參與正在進行的交易。
實作 SmartDataSource
SmartDataSource
介面應由可以提供關聯式資料庫連線的類別實作。它擴充了 DataSource
介面,讓使用它的類別可以查詢是否應在給定操作後關閉連線。當您知道需要重複使用連線時,這種用法很有效率。
擴充 AbstractDataSource
AbstractDataSource
是 Spring DataSource
實作的 abstract
基礎類別。它實作了所有 DataSource
實作通用的程式碼。如果您要編寫自己的 DataSource
實作,則應擴充 AbstractDataSource
類別。
使用 SingleConnectionDataSource
SingleConnectionDataSource
類別是 SmartDataSource
介面的實作,它封裝了一個單一的 Connection
,該連線在每次使用後都不會關閉。這不支援多線程。
如果任何客户端程式碼在假設池化連線的情況下呼叫 close
(例如在使用持久性工具時),您應該將 suppressClose
屬性設定為 true
。此設定會傳回一個關閉抑制 Proxy,它封裝了實體連線。請注意,您不能再將其轉換為原生 Oracle Connection
或類似的物件。
SingleConnectionDataSource
主要是一個測試類別。它通常可以輕鬆地在應用程式伺服器外部,結合簡單的 JNDI 環境,測試程式碼。與 DriverManagerDataSource
相比,它始終重複使用相同的連線,避免過度建立實體連線。
使用 DriverManagerDataSource
DriverManagerDataSource
類別是標準 DataSource
介面的實作,它透過 Bean 屬性配置純 JDBC 驅動程式,並在每次都傳回新的 Connection
。
此實作對於 Jakarta EE 容器外部的測試和獨立環境很有用,可以作為 Spring IoC 容器中的 DataSource
Bean,也可以與簡單的 JNDI 環境結合使用。假設池化的 Connection.close()
呼叫會關閉連線,因此任何感知 DataSource
的持久性程式碼都應能正常運作。但是,即使在測試環境中,使用 JavaBean 樣式的連線池(例如 commons-dbcp
)也非常容易,因此幾乎總是最好使用此類連線池而不是 DriverManagerDataSource
。
使用 TransactionAwareDataSourceProxy
TransactionAwareDataSourceProxy
是目標 DataSource
的 Proxy。此 Proxy 封裝了目標 DataSource
,以增加對 Spring 管理交易的感知。在這方面,它類似於 Jakarta EE 伺服器提供的交易型 JNDI DataSource
。
除非必須呼叫現有程式碼並將標準 JDBC DataSource 介面實作傳遞給它,否則很少需要使用此類別。在這種情況下,您仍然可以讓此程式碼可用,同時讓此程式碼參與 Spring 管理的交易。通常最好使用更高等級的資源管理抽象化來編寫您自己的新程式碼,例如 JdbcTemplate 或 DataSourceUtils 。 |
有關更多詳細資訊,請參閱 TransactionAwareDataSourceProxy
javadoc。
使用 DataSourceTransactionManager
/ JdbcTransactionManager
DataSourceTransactionManager
類別是單一 JDBC DataSource
的 PlatformTransactionManager
實作。它將來自指定 DataSource
的 JDBC Connection
繫結到目前執行的線程,可能允許每個 DataSource
一個線程綁定的 Connection
。
應用程式碼需要透過 DataSourceUtils.getConnection(DataSource)
而不是 Java EE 的標準 DataSource.getConnection
檢索 JDBC Connection
。它會擲回未檢查的 org.springframework.dao
例外,而不是已檢查的 SQLExceptions
。所有框架類別(例如 JdbcTemplate
)都隱含地使用此策略。如果未使用交易管理器,則查找策略的行為與 DataSource.getConnection
完全相同,因此可以在任何情況下使用。
DataSourceTransactionManager
類別支援儲存點 (PROPAGATION_NESTED
)、自訂隔離等級和逾時,這些逾時會套用為適當的 JDBC statement 查詢逾時。為了支援後者,應用程式碼必須使用 JdbcTemplate
或為每個建立的 statement 呼叫 DataSourceUtils.applyTransactionTimeout(..)
方法。
您可以在單一資源案例中使用 DataSourceTransactionManager
而不是 JtaTransactionManager
,因為它不需要容器支援 JTA 交易協調器。在這些交易管理器之間切換只是組態問題,前提是您堅持所需的連線查找模式。請注意,JTA 不支援儲存點或自訂隔離等級,並且具有不同的逾時機制,但在 JDBC 資源和 JDBC commit/rollback 管理方面,它表現出類似的行為。
對於 JTA 樣式的實際資源連線的延遲檢索,Spring 為目標連線池提供了對應的 DataSource
Proxy 類別:請參閱 LazyConnectionDataSourceProxy
。這對於可能沒有實際 statement 執行的空交易(在這種情況下永遠不會提取實際資源)特別有用,並且在路由 DataSource
前面也很有用,這意味著要考慮交易同步的唯讀標誌和/或隔離等級(例如,IsolationLevelDataSourceRouter
)。
LazyConnectionDataSourceProxy
也為在唯讀交易期間使用的唯讀連線池提供了特殊支援,避免在從主要連線池提取 JDBC 連線時,在每個交易的開始和結束時切換 JDBC Connection 的唯讀標誌的額外負擔(這可能會因 JDBC 驅動程式而異而成本高昂)。
從 5.3 開始,Spring 提供了擴充的 JdbcTransactionManager 變體,它在 commit/rollback 上新增了例外轉換功能(與 JdbcTemplate 對齊)。DataSourceTransactionManager 只會永遠擲回 TransactionSystemException (類似於 JTA),而 JdbcTransactionManager 會將資料庫鎖定失敗等轉換為對應的 DataAccessException 子類別。請注意,應用程式碼需要為此類例外做好準備,而不僅僅是預期 TransactionSystemException 。在這種情況下,建議選擇 JdbcTransactionManager 。 |
在例外行為方面,JdbcTransactionManager
大致相當於 JpaTransactionManager
,也相當於 R2dbcTransactionManager
,彼此充當直接的同伴/替代品。另一方面,DataSourceTransactionManager
相當於 JtaTransactionManager
,並且可以在那裡充當直接替代品。