バッチINSERT
s(defaultBatchValue
)および質量SELECT
s(defaultRowPrefetch
)を高速化するために、特定のOracle JDBC接続プロパティを設定する必要があります。私は suggestions DBCPでこれを達成する方法を得ました(M. Deinumに感謝)が、次のようにしたい:
私は将来的に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}
アクチュエータは、私のコードがデータソースを置き換えたことを示しています:
しかし、設定はアクティブ化されていません。これは、アプリケーションのプロファイリング中に表示されます。 defaultRowPrefetch
はまだ10
にあるため、SELECT
sは1000
がアクティブになっている場合よりもずっと遅くなります。
プールの設定 connectionProperties が機能するはずです。それらはJDBCドライバーに渡されます。これをapplication.propertiesに追加します。
spring.datasource.connectionProperties: defaultRowPrefetch=1000;defaultBatchValue=1000
編集(背景情報の一部):
また、spring.datasource。*を介して任意のDataSource実装固有のプロパティを設定できることに注意してください。詳細については、使用している接続プール実装のドキュメントを参照してください。
ソース: spring-bootドキュメント
Spring Bootは長い間EOLだったので、新しいデフォルトの接続プールHikariでSpring Boot 2.1に切り替えました。ここでの解決策はさらに簡単であり、application.propertiesまたは(ここに示すように)application.ymlで実行できます。
spring:
datasource:
hikari:
data-source-properties:
defaultRowPrefetch: 1000
(実際の構成では、他にもいくつかの構成項目がありますが、質問の対象ではないので、例では省略しています)
@Cyrilの回答を補足する追加情報。あなたが賛成したい場合は、私の答えではなく、彼の答えを使用してください。
データベース接続の作成中に最終的に使用される追加の接続プロパティを設定するのがいかに簡単であるか、少し戸惑いました。だから私は少し研究をしました。
spring.datasource.connectionProperties
はnotが 参照に記載されています 。このため、 issue を作成しました。 Spring Boot YMLエディター を使用した場合、どのプロパティがサポートされているかがわかりました。 [〜#〜] sts [〜#〜] がapplication.yml
を作成して Ctrl+Space:
relaxed binding のため、ダッシュは関係ありませんが、文字どおり解釈すると、プロパティ名はspring.datasource.connection-properties
になります。
Application.ymlの正しい設定は次のようになります:
spring:
datasource:
connection-properties: defaultBatchValue=1000;defaultRowPrefetch=1000
...
これは、私のperf4jの質量SELECT
sの測定によって証明されたものです。
前:
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に短縮され、パフォーマンスが大幅に向上します。
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;
}
}