如何在 Spring Boot 1.3.x 中使用默认 Tomcat 连接池在 DataSource 上设置自定义连接属性

How to set custom connection properties on DataSource in Spring Boot 1.3.x with default Tomcat connection pool

我需要设置一些特定的 Oracle JDBC 连接属性以加快批处理 INSERTs (defaultBatchValue) 和批量 SELECTs (defaultRowPrefetch). 我知道 如何使用 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;
}

在日志中我可以看到我正在创建正确的数据源:

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 比激活 1000 时要慢得多。

设置池 connectionProperties 应该可以。这些将被传递给 JDBC 驱动程序。将此添加到 application.properties:

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

编辑(一些背景信息):

Note also that you can configure any of the DataSource implementation specific properties via spring.datasource.*: refer to the documentation of the connection pool implementation you are using for more details.

来源:spring-boot documentation

一些额外的信息来补充@Cyril 的回答。如果您想投票,请使用他的回答,而不是我的。

我有点困惑设置最终在创建数据库连接时使用的附加连接属性是多么容易。所以我做了一点研究。

spring.datasource.connectionProperties 而不是 reference. I created an issue 中提到的,因为这个。 如果我在创建 application.yml 并按 Ctrl+Space:

时使用了 Spring Boot YML editor, I would have seen which properties are supported. Here is what STS 建议

由于 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 毫秒,这是一个巨大的性能提升。

在 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;
    }
}

由于 Spring Boot 已经停产很长时间了,我切换到 Spring Boot 2.1 及其新的默认连接池 Hikari。这里的解决方案更简单,可以在 application.properties 或(如此处所示)application.yml:

中完成
spring:
  datasource:
    hikari:
      data-source-properties:
        defaultRowPrefetch: 1000

(在实际配置中会有其他几个配置项,但由于他们对所问的问题不感兴趣,所以我只是在我的示例中将它们排除在外)