web-dev-qa-db-fra.com

Comment définir des propriétés de connexion personnalisées sur DataSource dans Spring Boot 1.3.x avec le pool de connexions Tomcat par défaut

J'ai besoin de définir certaines propriétés de connexion Oracle JDBC spécifiques afin d'accélérer le lot INSERTs (defaultBatchValue) et la masse SELECTs (defaultRowPrefetch). J'ai suggestions comment y parvenir avec DBCP (Merci à M. Deinum) mais je voudrais:

  • conserver le pool de connexions Tomcat jdbc par défaut
  • garder application.yml pour la configuration

Je pensais à une demande de fonctionnalité pour prendre en charge spring.datasource.custom_connection_properties ou similaire à l'avenir et à cause de cela a essayé de prétendre que c'était déjà possible. J'ai fait cela en transmettant les informations pertinentes lors de la création de la DataSource et en manipulant la création de la DataSource comme ceci:

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

Dans les journaux, je peux voir que je crée la bonne source de données:

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}

L'actionneur me montre que mon code a remplacé la source de données:

enter image description here

Mais les paramètres ne sont pas activés, ce que je peux voir lors du profilage de l'application. defaultRowPrefetch est toujours à 10 ce qui fait que mes SELECTs sont beaucoup plus lents qu'ils ne le seraient si 1000 a été activé.

9
Marged

La définition des pools connectionProperties devrait fonctionner. Ceux-ci seront transmis au pilote JDBC. Ajoutez ceci à application.properties:

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

Modifier (quelques informations générales):

Notez également que vous pouvez configurer n'importe quelle propriété spécifique de l'implémentation de DataSource via spring.datasource. *: Reportez-vous à la documentation de l'implémentation du pool de connexions que vous utilisez pour plus de détails.

source: documentation Spring-boot

9
Cyril

Comme Spring Boot est EOL depuis longtemps, je suis passé à Spring Boot 2.1 avec son nouveau pool de connexions par défaut Hikari. Ici, la solution est encore plus simple et peut être effectuée dans le fichier application.properties ou (comme illustré ici) application.yml:

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

(Dans une configuration réelle, il y aurait plusieurs autres éléments de configuration mais comme ils ne sont pas intéressants pour la question posée, je les ai simplement laissés de côté dans mon exemple)

2
Marged

Quelques informations supplémentaires pour compléter la réponse de @Cyril. Si vous voulez voter, utilisez sa réponse, pas la mienne.

J'étais un peu perplexe à quel point il est facile de définir des propriétés de connexion supplémentaires qui finalement seront utilisées lors de la création de la connexion à la base de données. J'ai donc fait un peu de recherche.

spring.datasource.connectionProperties n'est pas mentionné dans le référence . J'ai créé un problème à cause de cela. Si j'avais utilisé éditeur Spring Boot YML , j'aurais vu quelles propriétés sont prises en charge. Voici ce que STS suggère lorsque vous créez un application.yml et appuyez sur Ctrl+Space:

Autocomplete for spring.datasource

Le tiret n'a pas d'importance à cause de liaison relâchée mais si vous l'interprétez littéralement, le nom de la propriété est spring.datasource.connection-properties.

La configuration correcte dans application.yml ressemble à ceci:

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

Cela est honoré, ce qui est prouvé par mes mesures perf4j de masse SELECTs.

Avant:

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

Après:

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

Le temps nécessaire pour terminer l'instruction SQL passe de 1377 ms à 147, ce qui représente un énorme gain de performances.

2
Marged

Après avoir fouillé un peu dans le code Tomcat, j'ai trouvé que la dataSource.getPoolProperties().getDbProperties() est l'objet Properties qui sera réellement utilisé pour générer des connexions pour le pool.

Si vous utilisez l'approche BeanPostProcessor mentionnée par @ m-deinum, mais que vous l'utilisez à la place pour remplir les dbProperties comme cela, vous devriez pouvoir ajouter les propriétés d'une manière qui les rend collantes et être transmis au pilote 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