Как установить настраиваемые свойства соединения в DataSource в Spring Boot 1.3.x с пулом соединений Tomcat по умолчанию

Мне нужно установить некоторые определенные свойства соединения Oracle JDBC, чтобы ускорить пакетные INSERTs (defaultBatchValue) и массовые SELECTs (defaultRowPrefetch). Я получил предложения, как достичь это с 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;
}

В журналах я вижу, что я создаю правильный источник данных:

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 был активирован.


person Marged    schedule 18.01.2016    source источник
comment
Изменение свойств не сработает, это не те свойства, которые вы хотите изменить...   -  person M. Deinum    schedule 18.01.2016
comment
@M.Deinum M.Deinum Я думал, что это свойства, которые передаются при подключении к драйверу JDBC. Чем они отличаются от того, что я думал?   -  person Marged    schedule 18.01.2016
comment
Нет, они не передаются при подключении. Это внутренние свойства, используемые DataSourceBuilder, и они содержат лишь небольшое количество полезных свойств для внутреннего использования.   -  person M. Deinum    schedule 18.01.2016
comment
Вы правы, я выполнил это в отладчике и увидел, что даже если DataSourceBuilder будет учитывать эти свойства, tomcat jdbc DataSource/~Proxy не предоставляет для этого прямого установщика.   -  person Marged    schedule 18.01.2016


Ответы (4)


Настройка пулов connectionProperties должны работать. Они будут переданы драйверу JDBC. Добавьте это в application.properties:

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

Изменить (некоторая справочная информация):

Также обратите внимание, что вы можете настроить любые конкретные свойства реализации DataSource через spring.datasource.*: для получения более подробной информации см. документацию по реализации пула соединений, которую вы используете.

источник: документация по весенней загрузке

person Cyril    schedule 18.01.2016
comment
Кажется, это работает для свойств, которые передаются в URL-адресе jdbc. В моем сценарии defaultRowPrefetch необходимо передать в наборе Properties, который является вторым параметром, используемым в getConnection(String url, Properties prop), и следует сразу после URL-адреса jdbc. Но тем не менее спасибо за ваше редактирование. - person Marged; 19.01.2016
comment
Как упоминалось здесь ведущим разработчиком Spring Boot, в версии 1.4 это свойство больше не существует. - person Dieter Hubau; 15.02.2017

Некоторая дополнительная информация, дополняющая ответ @Cyril. Если вы хотите проголосовать, используйте его ответ, а не мой.

Я был немного озадачен тем, как легко установить дополнительные свойства подключения, которые в конечном итоге используются при создании подключения к базе данных. Поэтому я провел небольшое исследование.

spring.datasource.connectionProperties не упоминается в ссылка. Из-за этого я создал проблему. Если бы я использовал YML-редактор Spring Boot, я бы увидел какие свойства поддерживаются. Вот что предлагает STS, когда вы создаете application.yml и нажимаете Ctrl+Space:

Автозаполнение для spring.datasource

Дефис не имеет значения из-за расслабленная привязка, но если вы интерпретируете это буквально, имя свойства будет spring.datasource.connection-properties.

Правильная настройка в application.yml выглядит так:

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

Это соблюдается, что подтверждается моими perf4j измерениями массы SELECTs.

До:

2016-01-19 08:58:32.604 ИНФОРМАЦИЯ 15108 --- [главная] org.perf4j.TimingLogger: начало [1453190311227] время [1377] тег [получить элементы]

После:

2016-01-19 08:09:18.214 ИНФОРМАЦИЯ 9152 --- [главная] org.perf4j.TimingLogger: начало [1453187358066] время [147] тег [получить элементы]

Время, затрачиваемое на выполнение оператора SQL, снижается с 1377 мс до 147 мс, что является огромным приростом производительности.

person Marged    schedule 19.01.2016
comment
Это не упоминается, потому что это не общедоступное свойство. Это работает, потому что вы используете Tomcat JDBC, если бы вы использовали, например, Commons DBCP или пул на основе HikariCP, это свойство было бы недоступно и не работало бы. Это связано с привязкой, которая работает (возможно, это функция, которую следует задокументировать). - person M. Deinum; 19.01.2016
comment
Вы правы, для других пулов соединений нам нужен подход, который вы показали в другой мой вопрос. Но поскольку пул Tomcat JDBC используется по умолчанию, не мешало бы упомянуть конкретные параметры конфигурации ;-) Из-за этого я создал проблему на github. - person Marged; 19.01.2016
comment
Как я пытался прояснить, по умолчанию нет... Это зависит от ваших зависимостей. - person M. Deinum; 19.01.2016
comment
@ M.Deinum Возможно, мы просто говорим об определении значения по умолчанию. Мое определение по умолчанию в этом случае — это то, что используется, когда я не выбираю другую зависимость пула соединений. Поскольку контейнером по умолчанию в Spring Boot является Tomcat, вы автоматически получите пул Tomcat JDBC (если вы не измените это) - person Marged; 19.01.2016
comment
С точки зрения кода по умолчанию нет, это то, что для меня ведущее... Обнаружение всегда выполняется... - person M. Deinum; 19.01.2016
comment
@M.Deinum Для меня метод org.springframework.boot.autoconfigure.jdbc.DataSourceBuilders findType(), который запускается в Tomcat JDBC Pool и останавливается, как только находит совпадение, достаточно по умолчанию. По коду ;-) - person Marged; 19.01.2016
comment
На сегодняшний день Tomcat JDBC больше не является пулом по умолчанию. Spring Boot теперь предпочитает HikariCP. - person Peter Wippermann; 07.08.2019

Поскольку Spring Boot уже давно является EOL, я перешел на Spring Boot 2.1 с его новым пулом соединений по умолчанию Hikari. Здесь решение еще проще и может быть сделано в application.properties или (как показано здесь) application.yml:

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

(В реальной конфигурации было бы несколько других элементов конфигурации, но, поскольку они не представляют интереса для заданного вопроса, я просто не включил их в свой пример)

person Marged    schedule 12.04.2019

Немного покопавшись в коде Tomcat, я обнаружил, что dataSource.getPoolProperties().getDbProperties() — это объект Properties, который фактически будет использоваться для создания соединений для пула.

Если вы используете подход BeanPostProcessor, упомянутый @m-deinum, но вместо этого используете его для заполнения 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;
    }
}
person Russell B    schedule 13.09.2016