7.1 Groupe de connexion

Aujourd'hui, nous allons apprendre à travailler avec la base de données de manière encore plus professionnelle. Et maintenant, nous allons parler du pool de threads, ou pool de connexions en anglais.

La connexion à la base de données prend un certain temps. Surtout si la base de données est distante. Si nous établissons une connexion à la base de données pour chaque requête, la réponse de notre application sera incroyablement lente. Sans parler des ressources qu'il consommera.

Pour résoudre ces problèmes, il a été proposé de stocker les connexions à la base dans un ensemble appelé pool de threads.

Lorsque nous demandons une nouvelle connexion, le pool de connexions la crée, et lorsqu'il est fermé, il ne la ferme pas, mais l'enregistre dans le pool de connexions. Et si nous demandons à nouveau une connexion au pool de connexions, cela nous donnera l'une des anciennes au lieu d'en créer une nouvelle.

En fait, l'application fonctionne via un pilote spécial, qui est un wrapper pour un pilote JDBC standard et qui a des fonctionnalités supplémentaires pour travailler avec le pool. Cette situation peut être représentée comme suit :

pool de connexion

Le programmeur peut définir manuellement les paramètres du pool de connexion : le nombre de connexions actives, le délai d'attente, etc.

Pour des situations particulièrement extrêmes, vous pouvez écrire votre propre pool de connexions : une classe qui aura une liste de connexions. Cela remplacera la fonction de fermeture, qui ramènera la connexion dans la liste, et il y aura de nombreux autres avantages comme le minuteur de connexion ouverte. Lorsqu'il n'y a pas de connexion pendant une longue période, la connexion est fermée.

7.2* Interface DataSource et ConnectionPoolDataSource

Le pool de threads fonctionne généralement en tandem avec l'objet DataSource. Cet objet peut être considéré comme une abstraction d'une base de données distante. Le nom même de Data Source peut être littéralement traduit par Data Source. Ce qui est une sorte d'allusion.

Les objets DataSource sont utilisés pour obtenir une connexion physique à une base de données et sont une alternative à DriverManager. Il n'est pas nécessaire d'enregistrer le pilote JDBC. Il vous suffit de définir les paramètres appropriés pour établir une connexion etexécuter la méthode getConnection().

Lors de la création locale d'un objet de type DataSource (directement dans l'application), les paramètres de connexion sont définis par les méthodes appropriées fournies par le fournisseur du pilote JDBC. Ces méthodes ne sont pas définies par l'interface DataSource, car les paramètres de connexion au SGBD de différents fournisseurs peuvent différer en type et en nombre (par exemple, tous les SGBD n'exigent pas que le type de pilote ou de protocole réseau soit spécifié).

Ainsi, lorsque l'on travaille avec le SGBD Oracle, pour utiliser les méthodes set et get correspondantes, il est nécessaire d'obtenir un objet de type OracleDataSource, qui est une instance de la classe du même nom qui implémente l'interface DataSource. Par conséquent, cette façon de créer des objets de type DataSource rend votre code moins portable et moins dépendant de l'implémentation spécifique du pilote.

Voici un exemple de code illustrant l'utilisation locale d'objets de type DataSource.

import java.sql.*;
import javax.sql.*;
import oracle.jdbc.driver.*;
import oracle.jdbc.pool.*;

public class DataSource {
    public static void main(String[] args) {
    	try {
        	OracleDataSource ods = new OracleDataSource();

        	ods.setUser("root");
        	ods.setPassword("secret");
        	ods.setDriverType("thin");
        	ods.setDatabaseName("test");
        	ods.setServerName("localhost");
        	ods.setPortNumber(1521);

        	Connection connection = ods.getConnection();
        	System.out.println("Connection successful!!!");

    	} catch (SQLException se) {
        	se.printStackTrace();
    	}
    	System.out.println("Goodbye!");
	}
}

7.3* Interface JNDI

Les capacités complètes des objets de type DataSource se manifestent en combinaison avec l'utilisation de l'interface JNDI. JNDI est un service spécial (quelque chose comme un répertoire) pour les grandes applications serveur qui permet à un service d'établir une connexion avec un autre.

L'utilisation du service de nom et d'annuaire permet de stocker des objets de type DataSource préalablement créés par l'administrateur système avec des paramètres de connexion prédéfinis. Voici quelques-uns des noms de propriétés (paramètres) standard développés par Sun :

Nom de la propriété Type de données Java But
nom de la base de données Chaîne Nom de la base de données
nom du serveur Chaîne Nom du serveur
utilisateur Chaîne Nom d'utilisateur (ID)
mot de passe Chaîne Mot de passe de l'utilisateur
numéro de port entier Numéro de port du serveur SGBD

La combinaison des interfaces DataSource et JNDI joue un rôle clé dans le développement d'applications d'entreprise multiniveaux basées sur la technologie des composants J2EE.

Si vous utilisez une combinaison des interfaces DataSource et JNDI dans votre code d'application, il vous suffit de demander un objet de type DataSource au service de nommage et d'annuaire. Dans ce cas, les détails de la connexion et le code du programme dépendant d'une implémentation particulière du pilote sont cachés à l'application dans l'objet stocké dans le service de nom et d'annuaire.

Ainsi, le partage d'objets de type DataSource et JNDI passe par deux étapes qui s'effectuent indépendamment l'une de l'autre :

  1. Vous devez stocker l'objet nommé de type DataSource dans le service de nommage et d'annuaire à l'aide Context.bind()de l' extension javax.naming.
  2. Demandez un objet de type DataSource au service de nommage et d'annuaire de l'application à l'aide de l'extension Context.lookup(). Après cela, vous pouvez utiliser sa méthode DataSource.getConnection()pour obtenir une connexion à la base de données.

Voici un exemple d'utilisation conjointe de l'interface JNDI et d'un objet de type OracleDataSource.

// Create a key JNDI object
Hashtable env = new Hashtable();
env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, "file:JNDI");
Context ctx = new InitialContext(env);

// Get the DataSource object by its name
DataSource ods = (DataSource) ctx.lookup("myDatabase");

// Get the Connection from the DataSource object
Connection connection = ods.getConnection();
System.out.println("Connection successful!!!");

Nous n'analyserons pas le travail du JNDI. Cela sort du cadre de ce cours. Je veux juste que vous sachiez que cette approche est très courante dans les grandes applications. Ne vous perdez pas si vous voyez un code comme celui-ci à l'avenir.

Peu importe comment cela fonctionne. Vous devez juste savoir qu'avec un service JNDI, vous pouvez obtenir l'objet proxy de n'importe quel service enregistré dans le répertoire des services. C'est ainsi que vous obtenez l'objet DataSource et que vous l'utilisez pour travailler avec la base de données.

7.4 Exemples de pool de connexion

Revenons à notre point de départ - les pools de connexion.

Les programmeurs Java utilisent très souvent dans leurs programmes des bibliothèques contenant diverses implémentations de pools de connexions. Parmi eux, il y en a trois plus populaires :

  • Apache Commons DBCP
  • C3PO
  • HikariCP

Le projet Apache a été le premier à créer un bon pool de connexion, il est également utilisé à l'intérieur du serveur Web Tomcat. Un exemple de travail avec :

public class DBCPDataSource {

    private static BasicDataSource ds = new BasicDataSource();
    static {
    	ds.setUrl("jdbc:h2:mem:test");
    	ds.setUsername("user");
    	ds.setPassword("password");
    	ds.setMinIdle(5);
    	ds.setMaxIdle(10);
    	ds.setMaxOpenPreparedStatements(100);
    }

    public static Connection getConnection() throws SQLException {
    	return ds.getConnection();
    }

    private DBCPDataSource(){ }
}

Le deuxième pool très populaire est C3PO . Des noms étranges, j'en conviens. Le nom C3PO est une référence au robot c3po de Star Wars. Et aussi CP est l'abréviation de Connection Pool.

public class C3p0DataSource {

    private static ComboPooledDataSource cpds = new ComboPooledDataSource();
    static {
    	try {
        	cpds.setDriverClass("org.h2.Driver");
        	cpds.setJdbcUrl("jdbc:h2:mem:test");
        	cpds.setUser("user");
        	cpds.setPassword("password");
    	} catch (PropertyVetoException e) {
            // handle the exception
    	}
    }

    public static Connection getConnection() throws SQLException {
    	return cpds.getConnection();
    }

    private C3p0DataSource(){}
}

La documentation pour cela peut être trouvée sur la page officielle .

Et enfin, le pool de connexion le plus populaire à notre époque est HikariCP :

public class HikariCPDataSource {

    private static HikariConfig config = new HikariConfig();
    private static HikariDataSource ds;

    static {
    	config.setJdbcUrl("jdbc:h2:mem:test");
    	config.setUsername("user");
    	config.setPassword("password");
    	config.addDataSourceProperty("cachePrepStmts", "true");
    	config.addDataSourceProperty("prepStmtCacheSize", "250");
    	config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
    	ds = new HikariDataSource(config);
    }

    public static Connection getConnection() throws SQLException {
    	return ds.getConnection();
    }

    private HikariCPDataSource(){}
}

Voici sa page officielle GitHub .

Et un bon article sur la configuration.