1

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 でさまざまなパラメーターを試しましたが、違いはありません。

4

1 に答える 1

0

私の場合の問題は、sybase 用の jdbc ライブラリが古かったことだと思います。

于 2013-04-01T13:42:14.927 に答える