Spring アプリケーションで BasicDataSource を使用して JDBCTemplate との接続をプールしようとしています。私が読んだすべてのことから、これは非常に単純なはずです。XML で BasicDataSource を構成し、データ ソースを Bean に注入し、setter メソッドで新しい JDBCTemplate を作成するだけです。
これを行ったとき、自分のパフォーマンスがひどいことに気づきました。そこで、Spring の SingleConnectionDataSource に切り替えて、何が起こるかを確認したところ、パフォーマンスが大幅に向上しました。プロファイラー ツールで調査を開始したところ、BasicDataSource を使用すると、クエリごとに新しい接続が作成されていることに気付きました。
さらに調査すると、クエリの終了後に接続が閉じられている場所がわかります。具体的には、Spring の DataSourceUtil クラスで:
public static void doReleaseConnection(Connection con, DataSource dataSource) throws SQLException {
if (con == null) {
return;
}
if (dataSource != null) {
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && connectionEquals(conHolder, con)) {
// It's the transactional Connection: Don't close it.
conHolder.released();
return;
}
}
// Leave the Connection open only if the DataSource is our
// special SmartDataSoruce and it wants the Connection left open.
if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {
logger.debug("Returning JDBC Connection to DataSource");
con.close();
}
}
私が気づいたことは、接続を開いたままにする「SmartDataSource」の特別なロジックがあることです。これは、私が見ていた動作を部分的に説明しています: SingleConnectionDataSource は SmartDataSource を実装しているため、接続は閉じられません。ただし、BasicDataSource を使用すると、接続の close() メソッドは接続をプールに返すだけだと思いました。しかし、プロファイラーで何が起こっているかを見ると、実際には sybase 接続で close メソッドが呼び出されています。
最後に 1 つ (これはこれから調査します): 一部のクエリ (データベースへのコミットを含む) に TransactionTemplate を使用しますが、単純なクエリは transactionTemplate 内にありません。それが問題と関係があるかどうかはわかりません。
編集1:
OK、プロジェクトから少し離れた後、ようやく調査する時間ができました。問題を示す非常に簡単なテストを次に示します。
public class DBConnectionPoolTest {
@Autowired
@Qualifier("myDataSource")
private DataSource dataSource;
@Test
public void test() throws Exception{
JdbcTemplate template = new JdbcTemplate(dataSource);
StopWatch sw = new StopWatch();
sw.start();
for(int i=0; i<1000; i++){
template.queryForInt("select count(*) from mytable");
}
sw.stop();
System.out.println("TIME: " + sw.getTotalTimeSeconds() + " seconds");
}}
これが私の2つのデータソース構成です。
<bean id="myDataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
最初の構成でテストを実行すると、約 2.1 秒かかります。2 番目の構成で実行すると、約 4.5 秒かかります。maxActive=1 や testOnBorrow=false を設定するなど、BasicDataSource でさまざまなパラメーターを試しましたが、違いはありません。