web-dev-qa-db-fra.com

Meilleures pratiques des pools de connexions JDBC Spring

J'ai une application Spring JDBC de base avec une jolie configuration de base:

<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName" value="Oracle.jdbc.OracleDriver"/>
   <property name="url" value="jdbc:Oracle:thin:@1.1.1.1:1521:XXX"/>
   <property name="username" value="username"/>
   <property name="password" value="password"/>
</bean>

<bean id="dbThing" class="com.DbThing">
   <property name="dataSource" ref="myDataSource"/>
</bean>

Je voudrais introduire un pool de connexion et après avoir lu plusieurs threads ici sur SO, je suis un peu confus quant à la bibliothèque de pooling à utiliser.

Les bibliothèques qui semblent avoir plus de crédits sur SO sont CP30 et DBCP . Étant donné que j'utilise Oracle, je pourrais également utiliser le fichier pooled data source proposé par le pilote . Je comprends qu'il existe davantage de bibliothèques, par exemple les nouvelles bibliothèques de pooling Apache Tomcat 7.

Y a-t-il une bibliothèque que je devrais vraiment éviter? 

Existe-t-il une configuration recommandée que je devrais utiliser avec une bibliothèque donnée?

Une "histoire de guerre" que vous souhaitez partager?

37
Luciano Fiandesio

Le développement de C3PO et DBCP est en perte de vitesse car ils sont matures. J'ai vu ces deux pilotes être en mesure de prendre en charge des centaines de transactions par seconde.

Le pool Tomcat est un pilote DBCP retravaillé et mis à jour. MyBatis 3.0 contient également sa propre implémentation de pooling qui, basée sur l'inspection de code, semble solide. Enfin, il y a BoneCP qui prétend avoir les meilleures performances. Je n'ai encore utilisé aucun de ceux-ci sur un projet.

Le meilleur conseil est probablement de choisir n'importe lequel d'entre eux. Le printemps facilite l’échange ultérieur.

20
AngerClown

Au lieu de BoneCP, avez-vous peut-être essayé le pool de connexions à la base de données propre à Oracle? 

J'ai eu de bonnes expériences au cours des dernières semaines, donc cela vaut peut-être la peine de tenter le coup. De plus, je suppose qu'Oracle sait quelque chose à propos de la création d'un pool de connexions, en particulier lorsqu'il est associé à sa propre base de données.

<bean id="dataSource" class="Oracle.jdbc.pool.OracleConnectionPoolDataSource">
    <property name="URL" value="${jdbc.url}" />
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

UPDATE: si vous utilisez l'un des derniers pilotes JDBC Oracle (11.2.0.1+), vous pouvez essayer le nouveau pool de connexions universelles. La OracleConnectionPoolDataSource semble être officiellement déconseillée en faveur de ce pool. Cependant, certains utilisateurs ont signalé des erreurs lors de l’utilisation, c’est peut-être trop tôt. Je suis en mesure d’utiliser les derniers pilotes JDBC d’Oracle. Je vais donc essayer et mettre à jour le logiciel dès que nous aurons des informations à ce sujet.

Plus d'informations sur ce fil SO: Oracle UCP

17
quantum

BoneCP réclamait, mais un nouvel outil nommé HiKariCP a été introduit. Il a surmonté de nombreux inconvénients qui étaient présents dans les outils de passe. Vous pouvez le configurer en modifiant le application-context.xml ci-dessous.

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
  <property name="maximumPoolSize" value="10" />
  <property name="minimumPoolSize" value="2" />
  <property name="dataSourceClassName" 
            value="Oracle.jdbc.pool.OracleDataSource" />
  <property name="dataSourceProperties" ref="props" />
  <property name="poolName" value="springHikariCP" />
</bean>

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
      <constructor-arg ref="hikariConfig" />
</bean>

<util:properties id="props" location="classpath:datasource.properties"/>

où dans database.properties vous devriez fournir des détails de base de données comme ci-dessous

 url=jdbc:Oracle:thin:@IP:port:SID/Databasename
 user=usernmae
 password=password

Pour une démo appropriée, vous pouvez utiliser ce lien

9
Bhargav Modi

Vous pouvez certainement utiliser C3P0, ceci est développé pour la solution d'entreprise. Pour vérifier les avantages, vous pouvez suivez cette réponse .

Voici l'exemple de code d'intégration:

@Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager =
                new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

Ce haricot sert à obtenir JpaTransactionManager.

@Primary
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

    LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactoryBean.setDataSource(dataSource());
    entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
    entityManagerFactoryBean.setPackagesToScan("YOUR.DATABSE.ENTITY.PACKAGE");
    entityManagerFactoryBean.setJpaProperties(hibProperties());

    return entityManagerFactoryBean;
}

Ce haricot sert à obtenir LocalContainerEntityManagerFactoryBean. Cela prend DataSource, PersistenceProviderClass, Nom du package d'entité PackagesToScan et JpaProperties de hibProperties().

@Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

private Properties hibProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        return properties;
    }

Ici, env value are comming from application.properties

Vérifier les propriétés du soufflet:

hibernate.dialect: org.hibernate.dialect.Oracle12cDialect
hibernate.show_sql: false
hibernate.hbm2ddl.auto: none

La partie principale est l’installation de DataSource. C'est donné ci-dessous:

@Bean
    public ComboPooledDataSource dataSource(){
        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        try {
            dataSource.setDriverClass(env.getProperty("db.driver"));
            dataSource.setJdbcUrl(env.getProperty("db.url"));
            dataSource.setUser(env.getProperty("db.username"));
            dataSource.setPassword(env.getProperty("db.password"));
            dataSource.setMinPoolSize(Integer.parseInt(env.getProperty("minPoolSize")));
            dataSource.setMaxPoolSize(Integer.parseInt(env.getProperty("maxPoolSize")));
            dataSource.setMaxIdleTime(Integer.parseInt(env.getProperty("maxIdleTime")));
            dataSource.setMaxStatements(Integer.parseInt(env.getProperty("maxStatements")));
            dataSource.setMaxStatementsPerConnection(Integer.parseInt(env.getProperty("maxStatementsPerConnection")));
            dataSource.setMaxIdleTimeExcessConnections(10000);

        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

Il utilise ComboPooledDataSource qui prend de nombreux paramètres plus importants tels que maxPoolSize, MinPoolSize, MaxIdleSize etc. .Son paramètre d'environnement est donné ci-dessous:

db.driver: Oracle.jdbc.driver.OracleDriver // for Oracle
db.username: YOUR_USER_NAME
db.password: YOUR_USER_PASSWORD
db.url: DATABASE_URL
minPoolSize:5 // number of minimum poolSize
maxPoolSize:100 // number of maximum poolSize
maxIdleTime:5 // In seconds. After that time it will realease the unused connection.
maxStatements:1000
maxStatementsPerConnection:100
maxIdleTimeExcessConnections:10000

Voici le code de travail complet:

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import Java.beans.PropertyVetoException;
import Java.util.Properties;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories
@PropertySource("classpath:application.properties")
@Scope("singleton")
public class TestDataSource {

    @Autowired
    private Environment env;

    @Qualifier("dataSource")
    @Autowired
    private DataSource dataSource;

    @Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager =
                new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    @Primary
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        entityManagerFactoryBean.setPackagesToScan("YOUR.PACKAGE.NAME");
        entityManagerFactoryBean.setJpaProperties(hibProperties());

        return entityManagerFactoryBean;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Bean
    public ComboPooledDataSource dataSource(){
        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        try {
            dataSource.setDriverClass(env.getProperty("db.driver"));
            dataSource.setJdbcUrl(env.getProperty("db.url"));
            dataSource.setUser(env.getProperty("db.username"));
            dataSource.setPassword(env.getProperty("db.password"));
            dataSource.setMinPoolSize(Integer.parseInt(env.getProperty("minPoolSize")));
            dataSource.setMaxPoolSize(Integer.parseInt(env.getProperty("maxPoolSize")));
            dataSource.setMaxIdleTime(Integer.parseInt(env.getProperty("maxIdleTime")));
            dataSource.setMaxStatements(Integer.parseInt(env.getProperty("maxStatements")));
            dataSource.setMaxStatementsPerConnection(Integer.parseInt(env.getProperty("maxStatementsPerConnection")));
            dataSource.setMaxIdleTimeExcessConnections(10000);

        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

    private Properties hibProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        return properties;
    }
}

Une autre chose. Voici le lien gradle

compile group: 'org.hibernate', name: 'hibernate-c3p0', version: '5.2.10.Final'

J'espère que cela vous aidera ... Merci. :)

0
Md. Sajedul Karim