web-dev-qa-db-ja.com

デフォルトのTomcat接続プールでSpring Boot 1.3.xのDataSourceにカスタム接続プロパティを設定する方法

バッチINSERTs(defaultBatchValue)および質量SELECTs(defaultRowPrefetch)を高速化するために、特定のOracle JDBC接続プロパティを設定する必要があります。私は suggestions DBCPでこれを達成する方法を得ました(M. Deinumに感謝)が、次のようにしたい:

  • デフォルトのTomcat jdbc接続プールを維持する
  • 設定のためにapplication.ymlを保持します

私は将来的にspring.datasource.custom_connection_propertiesまたは同様のものをサポートする機能のリクエストについて考えていましたが、これにより、これはすでに可能であると主張しようとしました。これを行うには、DataSourceの作成中に関連情報を渡し、DataSourceの作成を次のように操作しました。

@Bean
public DataSource dataSource() {
    DataSource ds = null;

    try {
        Field props = DataSourceBuilder.class.getDeclaredField("properties");
        props.setAccessible(true);
        DataSourceBuilder builder = DataSourceBuilder.create();
        Map<String, String> properties = (Map<String, String>) props.get(builder);

        properties.put("defaultRowPrefetch", "1000");
        properties.put("defaultBatchValue", "1000");

        ds = builder.url( "jdbc:Oracle:thin:@xyz:1521:abc" ).username( "ihave" ).password( "wonttell" ).build();

        properties = (Map<String, String>) props.get(builder);

        log.debug("properties after: {}", properties);
    } ... leaving out the catches ...
    }
    log.debug("We are using this datasource: {}", ds);
    return ds;
}

ログで、正しいDataSourceを作成していることがわかります。

2016-01-18 14:40:32.924 DEBUG 31204 --- [           main] d.a.e.a.c.config.DatabaseConfiguration   : We are using this datasource: org.Apache.Tomcat.jdbc.pool.DataSource@19f040ba{ConnectionPool[defaultAutoCommit=null; ...

2016-01-18 14:40:32.919 DEBUG 31204 --- [           main] d.a.e.a.c.config.DatabaseConfiguration   : properties after: {password=wonttell, driverClassName=Oracle.jdbc.OracleDriver, defaultRowPrefetch=1000, defaultBatchValue=1000, url=jdbc:Oracle:thin:@xyz:1521:abc, username=ihave}

アクチュエータは、私のコードがデータソースを置き換えたことを示しています:

enter image description here

しかし、設定はアクティブ化されていません。これは、アプリケーションのプロファイリング中に表示されます。 defaultRowPrefetchはまだ10にあるため、SELECTsは1000がアクティブになっている場合よりもずっと遅くなります。

9
Marged

プールの設定 connectionProperties が機能するはずです。それらはJDBCドライバーに渡されます。これをapplication.propertiesに追加します。

spring.datasource.connectionProperties: defaultRowPrefetch=1000;defaultBatchValue=1000

編集(背景情報の一部):

また、spring.datasource。*を介して任意のDataSource実装固有のプロパティを設定できることに注意してください。詳細については、使用している接続プール実装のドキュメントを参照してください。

ソース: spring-bootドキュメント

9
Cyril

Spring Bootは長い間EOLだったので、新しいデフォルトの接続プールHikariでSpring Boot 2.1に切り替えました。ここでの解決策はさらに簡単であり、application.propertiesまたは(ここに示すように)application.ymlで実行できます。

spring:
  datasource:
    hikari:
      data-source-properties:
        defaultRowPrefetch: 1000

(実際の構成では、他にもいくつかの構成項目がありますが、質問の対象ではないので、例では省略しています)

2
Marged

@Cyrilの回答を補足する追加情報。あなたが賛成したい場合は、私の答えではなく、彼の答えを使用してください。

データベース接続の作成中に最終的に使用される追加の接続プロパティを設定するのがいかに簡単であるか、少し戸惑いました。だから私は少し研究をしました。

spring.datasource.connectionPropertiesnot参照に記載されています 。このため、 issue を作成しました。 Spring Boot YMLエディター を使用した場合、どのプロパティがサポートされているかがわかりました。 [〜#〜] sts [〜#〜]application.ymlを作成して Ctrl+Space

Autocomplete for spring.datasource

relaxed binding のため、ダッシュは関係ありませんが、文字どおり解釈すると、プロパティ名はspring.datasource.connection-propertiesになります。

Application.ymlの正しい設定は次のようになります:

spring:
    datasource:
        connection-properties: defaultBatchValue=1000;defaultRowPrefetch=1000
        ...

これは、私のperf4jの質量SELECTsの測定によって証明されたものです。

前:

2016-01-19 08:58:32.604 INFO 15108 --- [main] org.perf4j.TimingLogger:start [1453190311227] time [1377] tag [get elements]

後:

2016-01-19 08:09:18.214 INFO 9152 --- [main] org.perf4j.TimingLogger:start [1453187358066] time [147] tag [get elements]

SQLステートメントの完了にかかる時間は1377ミリ秒から147に短縮され、パフォーマンスが大幅に向上します。

2
Marged

Tomcatコードを少し調べたところ、dataSource.getPoolProperties().getDbProperties()は実際にプールの接続を生成するために使用されるPropertiesオブジェクトであることがわかりました。

@ m-deinumで言及されているBeanPostProcessorアプローチを使用するが、代わりにそれを使用してdbPropertiesにデータを入力する場合は、プロパティを固定して、 Oracleドライバーに渡されます。

import Java.util.Properties;
import org.Apache.Tomcat.jdbc.pool.DataSource;
import org.Apache.Tomcat.jdbc.pool.PoolConfiguration;

@Component
public class OracleConfigurer implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
        if (bean instanceof DataSource) {
            DataSource dataSource = (DataSource)bean;
            PoolConfiguration configuration = dataSource.getPoolProperties();
            Properties properties = configuration.getDbProperties();
            if (null == properties) properties = new Properties();
            properties.put("defaultRowPrefetch", 1000);
            properties.put("defaultBatchValue", 1000);
            configuration.setDbProperties(properties);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
        return bean;
    }
}
1
Russell B