データベース接続の制御
DataSource
を使用する
Spring は、DataSource
を介してデータベースへの接続を取得します。DataSource
は JDBC 仕様の一部であり、一般化された接続ファクトリです。コンテナーまたはフレームワークは、接続プールとトランザクション管理の課題をアプリケーションコードから隠すことができます。開発者として、データベースへの接続方法に関する詳細を知る必要はありません。それは、データソースを設定する管理者の責任です。ほとんどの場合、コードを開発およびテストするときに両方のロールを果たしますが、必ずしも本番データソースがどのように構成されているかを知る必要はありません。
Spring の JDBC レイヤーを使用する場合、JNDI からデータソースを取得するか、サードパーティが提供する接続プール実装を使用して独自のデータソースを構成することができます。従来の選択肢は、Bean スタイルの DataSource
クラスを備えた Apache Commons DBCP と C3P0 です。最新の JDBC 接続プールの場合は、代わりにビルダースタイルの API を備えた HikariCP を検討してください。
DriverManagerDataSource および SimpleDriverDataSource クラス(Spring ディストリビューションに含まれる)は、テスト目的でのみ使用してください! これらのバリアントはプーリングを提供せず、接続に対して複数のリクエストが行われたときにパフォーマンスが低下します。 |
次のセクションでは、Spring の DriverManagerDataSource
実装を使用します。他のいくつかの DataSource
バリアントについては後で説明します。
DriverManagerDataSource
を構成するには:
通常は JDBC 接続を取得するため、
DriverManagerDataSource
との接続を取得します。DriverManager
がドライバークラスをロードできるように、JDBC ドライバーの完全修飾クラス名を指定します。JDBC ドライバー間で異なる URL を提供します。(正しい値については、ドライバーのドキュメントを参照してください。)
データベースに接続するためのユーザー名とパスワードを入力します。
次の例は、DriverManagerDataSource
を構成する方法を示しています。
Java
Kotlin
XML
@Bean
DriverManagerDataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean
fun dataSource() = DriverManagerDataSource().apply {
setDriverClassName("org.hsqldb.jdbcDriver")
url = "jdbc:hsqldb:hsql://localhost:"
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"/>
次の 2 つの例は、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://localhost:");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean(destroyMethod = "close")
fun dataSource() = BasicDataSource().apply {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:hsql://localhost:"
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://localhost:");
dataSource.setUser("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean(destroyMethod = "close")
fun dataSource() = ComboPooledDataSource().apply {
driverClass = "org.hsqldb.jdbcDriver"
jdbcUrl = "jdbc:hsqldb:hsql://localhost:"
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
クラスは、JNDI から接続を取得し、必要に応じて接続を閉じるための static
メソッドを提供する便利で強力なヘルパークラスです。スレッドバインドされた JDBC Connection
と DataSourceTransactionManager
だけでなく、JtaTransactionManager
および JpaTransactionManager
もサポートします。
JdbcTemplate
は DataSourceUtils
接続アクセスを暗黙的に示し、すべての JDBC 操作の背後でそれを使用し、進行中のトランザクションに暗黙的に参加することに注意してください。
SmartDataSource
の実装
SmartDataSource
インターフェースは、リレーショナルデータベースへの接続を提供できるクラスによって実装する必要があります。DataSource
インターフェースを継承し、それを使用するクラスが、特定の操作後に接続を閉じる必要があるかどうかを照会できるようにします。この使用方法は、接続を再利用する必要があることがわかっている場合に効率的です。
AbstractDataSource
の拡張
AbstractDataSource
は、Spring の DataSource
実装の abstract
基本クラスです。すべての DataSource
実装に共通のコードを実装します。独自の DataSource
実装を作成する場合は、AbstractDataSource
クラスを継承する必要があります。
SingleConnectionDataSource
を使用する
SingleConnectionDataSource
クラスは、使用後に閉じられない単一の Connection
をラップする SmartDataSource
インターフェースの実装です。これはマルチスレッド対応ではありません。
プールされた接続を想定してクライアントコードが close
を呼び出す場合(永続性ツールを使用する場合など)、suppressClose
プロパティを true
に設定する必要があります。この設定は、物理接続をラップする緊密なプロキシを返します。これをネイティブ Oracle Connection
または同様のオブジェクトにキャストできないことに注意してください。
SingleConnectionDataSource
は主にテストクラスです。これにより、通常、単純な JNDI 環境と組み合わせて、アプリケーションサーバーの外部でコードを簡単にテストできます。DriverManagerDataSource
とは対照的に、常に同じ接続を再利用し、物理的な接続の過度の作成を回避します。
DriverManagerDataSource
を使用する
DriverManagerDataSource
クラスは、Bean プロパティを介してプレーン JDBC ドライバーを構成し、毎回新しい Connection
を返す標準 DataSource
インターフェースの実装です。
この実装は、Spring IoC コンテナー内の DataSource
Bean として、または単純な JNDI 環境と組み合わせて、Jakarta EE コンテナー外のテストおよびスタンドアロン環境に役立ちます。プールを想定した Connection.close()
呼び出しは接続を閉じるため、DataSource
-aware 永続性コードはすべて機能するはずです。ただし、テスト環境であっても JavaBean スタイルの接続プール(commons-dbcp
など)を使用するのは非常に簡単なので、そのような接続プールを DriverManagerDataSource
よりも使用することがほぼ常に望ましいです。
TransactionAwareDataSourceProxy
を使用する
TransactionAwareDataSourceProxy
は、ターゲット DataSource
のプロキシです。プロキシは、DataSource
をターゲットとしてラップし、Spring が管理するトランザクションの認識を追加します。この点で、Jakarta EE サーバーによって提供されるトランザクション JNDI DataSource
に似ています。
既存のコードを呼び出して標準 JDBC DataSource インターフェース実装を渡す必要がある場合を除いて、このクラスを使用することはめったにありません。この場合、このコードを引き続き使用可能にし、同時にこのコードを Spring 管理トランザクションに参加させることができます。一般に、JdbcTemplate や DataSourceUtils など、リソース管理用のより高いレベルの抽象化を使用して、独自の新しいコードを作成することをお勧めします。 |
詳細については、TransactionAwareDataSourceProxy
javadoc を参照してください。
DataSourceTransactionManager
/ JdbcTransactionManager
を使用する
DataSourceTransactionManager
クラスは、単一の JDBC DataSource
の PlatformTransactionManager
実装です。これは、指定された DataSource
から現在実行中のスレッドに JDBC Connection
をバインドし、DataSource
ごとに 1 つのスレッドバインド Connection
を可能にする可能性があります。
Java EE の標準 DataSource.getConnection
ではなく、JDBC Connection
から DataSourceUtils.getConnection(DataSource)
を取得するには、アプリケーションコードが必要です。チェックされた SQLExceptions
の代わりに、チェックされていない org.springframework.dao
例外がスローされます。すべてのフレームワーククラス ( JdbcTemplate
など) はこの戦略を暗黙的に使用します。トランザクションマネージャーで使用しない場合、検索戦略は DataSource.getConnection
とまったく同じように動作するため、どのような場合でも使用できます。
DataSourceTransactionManager
クラスは、セーブポイント (PROPAGATION_NESTED
)、カスタム分離レベル、適切な JDBC ステートメントクエリタイムアウトとして適用されるタイムアウトをサポートします。後者をサポートするには、アプリケーションコードで JdbcTemplate
を使用するか、作成されたステートメントごとに DataSourceUtils.applyTransactionTimeout(..)
メソッドを呼び出す必要があります。
単一リソースの場合は、コンテナーが JTA トランザクションコーディネーターをサポートする必要がないため、JtaTransactionManager
の代わりに DataSourceTransactionManager
を使用できます。必要な接続ルックアップパターンを守っていれば、これらのトランザクションマネージャー間の切り替えは構成だけの問題です。JTA はセーブポイントやカスタム分離レベルをサポートしておらず、異なるタイムアウトメカニズムを備えていますが、それ以外の点では、JDBC リソースおよび JDBC コミット / ロールバック管理に関して同様の動作を公開することに注意してください。
実際のリソース接続の JTA スタイルの遅延取得のために、Spring はターゲット接続プールに対応する DataSource
プロキシクラスを提供します。LazyConnectionDataSourceProxy
(Javadoc) を参照してください。これは、実際のステートメント実行のない潜在的に空のトランザクション (このようなシナリオでは実際のリソースをフェッチしない) の場合や、トランザクション同期読み取り専用フラグや分離レベル (たとえば、IsolationLevelDataSourceRouter
) を考慮するルーティング DataSource
の前で特に役立ちます。
LazyConnectionDataSourceProxy
は、読み取り専用トランザクション中に使用する読み取り専用接続プールの特別なサポートも提供し、プライマリ接続プールから JDBC 接続を取得するときに、各トランザクションの開始時と終了時に JDBC 接続の読み取り専用フラグを切り替えるオーバーヘッドを回避します ( JDBC ドライバーによってはコストがかかる場合があります)。
5.3 の時点で、Spring は、コミット / ロールバック時の例外変換機能を追加する拡張 JdbcTransactionManager バリアントを提供します ( JdbcTemplate と連携)。DataSourceTransactionManager は TransactionSystemException (JTA に類似) のみをスローしますが、JdbcTransactionManager はデータベースロックの失敗などを対応する DataAccessException サブクラスに変換します。アプリケーションコードは、TransactionSystemException だけを想定するのではなく、そのような例外に備えて準備する必要があることに注意してください。このようなシナリオでは、JdbcTransactionManager が推奨される選択肢です。 |
例外動作の点では、JdbcTransactionManager
は JpaTransactionManager
とほぼ同等であり、また R2dbcTransactionManager
とも同等であり、互いの直接のコンパニオン / 置換として機能します。一方、DataSourceTransactionManager
は JtaTransactionManager
と同等であり、JtaTransactionManager
の直接の代替として機能します。