31.10. Ensemble de connexions et source de données

JDBC 2 a introduit des fonctionnalités standard d'ensemble de connexions dans une API supplémentaire connue sous le nom du paquet optionnel de JDBC 2.0 (aussi connue en tant qu'extension standard de JDBC 2.0). Ces fonctionnalités ont depuis été inclus dans l'API au cœur de JDBC 3. Le pilote JDBC de PostgreSQL supporte ces fonctionnalités s'il a été compilé avec le JDK 1.3.x en combinaison avec le paquet optionnel de JDBC 2.0 (JDBC 2) ou avec le JDK 1.4 ou une version suivante (JDBC 3). La plupart des serveurs d'applications incluent le paquet optionnel de JDBC 2.0 mais il est aussi disponible séparément sur le site de téléchargement JDBC de Sun.

31.10.1. Aperçu

L'API JDBC fournit une interface client et serveur pour la gestion de pools de connexions. L'interface client est javax.sql.DataSource, qui est ce que le code de l'application utilisera typiquement pour récupérer une connexion à la base de données depuis ce pool. L'interface du serveur est javax.sql.ConnectionPoolDataSource. C'est la méthode utilisée par la plupart des serveurs d'application pour se créer une interface avec le pilote JDBC de PostgreSQL.

Dans un environnement avec un serveur d'applications, la configuration du serveur d'applications se référera typiquement à l'implémentation ConnectionPoolDataSource de PostgreSQL alors que le code composant de l'application obtiendra typiquement une implémentation du DataSource fournie par le serveur d'applications (et non pas par PostgreSQL).

Pour un environnement serveur sans serveur d'applications, PostgreSQL fournit deux implémentations de DataSource qu'une application peut utiliser directement. Une implémentation réalise la gestion de pool de connexions alors qu'une autre fournit des accès à ses connexions via l'interface de DataSource sans pool. Encore une fois, ces implémentations ne doivent pas être utilisées dans un environnement de serveur d'application sauf si le serveur d'application ne supporte pas l'interface ConnectionPoolDataSource.

31.10.2. Serveurs d'application : ConnectionPoolDataSource

PostgreSQL inclut une implémentation de ConnectionPoolDataSource pour JDBC 2 et une pour JDBC 3, comme montré dans Tableau 31-1.

Tableau 31-1. Implémentations de ConnectionPoolDataSource

JDBCClasse d'implémentation
2org.postgresql.jdbc2.optional.ConnectionPool
3org.postgresql.jdbc3.Jdbc3ConnectionPool

Les deux implémentations utilisent le même schéma de configuration. JDBC requiert qu'un ConnectionPoolDataSource soit configuré via des propriétés JavaBean, décrites dans Tableau 31-2, si bien qu'il y a des méthodes get et set pour chacune des propriétés.

Tableau 31-2. Propriétés de configuration de ConnectionPoolDataSource

PropriétéTypeDescription
serverNameStringNom d'hôte du serveur de bases de données PostgreSQL
databaseNameStringNom de la base de données PostgreSQL
portNumberint Port TCP sur lequel le serveur de bases de données PostgreSQL écoute (ou 0 pour utiliser le port par défaut)
userStringUtilisateur utilisé pour réaliser les connexions à la base de données
passwordStringMot de passe utilisé pour réaliser les connexions à la base de données
defaultAutoCommitboolean Les connexions doivent-elles activer la validation automatique (autocommit) lorsqu'elles sont fournies au demandeur. Par défaut à false pour désactiver la validation automatique.

Beaucoup de serveurs d'application utilisent une syntaxe style propriétés pour configurer leurs propriétés, donc il ne sera pas inhabituel d'entrer les propriétés avec un bloc de texte. Si le serveur d'application fournit un emplacement simple pour saisir toutes les propriétés, elles pourraient être listées ensemble comme ceci :

serverName=localhost
databaseName=test
user=testuser
password=testpassword

Ou, si les points virgules sont utilisés comme séparateurs au lieu des retours à la ligne, cela pourrait ressembler à ceci :

serverName=localhost;databaseName=test;user=testuser;password=testpassword

31.10.3. Applications : DataSource

PostgreSQL inclut deux versions de DataSource pour JDBC 2 et deux pour JDBC 3, comme le montre Tableau 31-3. Les implémentations ne ferment pas les connexions lorsque le client appelle la méthode close mais renvoie à la place les connexions dans un ensemble de connexions disponibles pour les autres clients. Ceci évite une surcharge pour l'ouverture et la fermeture des connexions et permet à un grand nombre de clients de partager un petit nombre de connexions à la base de données.

L'implémentation des sources de données en pool fournie ici ne dispose que de fonctionnalités limitées. Entre autres choses, les connexions ne sont jamais fermées jusqu'à ce que le pool soit lui-même fermé ; il n'existe pas de moyens de diminuer le pool. De même, les connexions demandées par les utilisateurs autres que celui de l'utilisateur configuré par défaut ne sont pas gérées dans ce pool. Beaucoup de serveurs d'application fournissent des fonctionnalités plus avancées et utilisent à la place l'implémentation ConnectionPoolDataSource.

Tableau 31-3. Implémentations de DataSource

JDBCGestion en ensembleClasse d'implémentation
2Nonorg.postgresql.jdbc2.optional.SimpleDataSource
2Ouiorg.postgresql.jdbc2.optional.PoolingDataSource
3Nonorg.postgresql.jdbc3.Jdbc3SimpleDataSource
3Ouiorg.postgresql.jdbc3.Jdbc3PoolingDataSource

Toutes les implémentations utilisent le même schéma de configuration. JDBC impose qu'une DataSource soit configurée via des propriétés JavaBean, affichées dans Tableau 31-4, si bien qu'il existe des méthodes get et set pour chacune de ces propriétés.

Tableau 31-4. Propriétés de configuration de DataSource

PropriétéTypeDescription
serverNameStringNom d'hôte du serveur de bases de données PostgreSQL
databaseNameStringNom de la base de données PostgreSQL
portNumberintPort TCP sur lequel le serveur de bases de données PostgreSQL est en écoute (ou 0 pour utiliser le port par défaut)
userStringUtilisateur utilisé pour réaliser les connexions à la base de données
passwordStringMot de passe utilisé pour réaliser les connexions à la base de données

Les implémentations de gestion de pools requièrent quelques propriétés supplémentaires de configuration, qui sont affichées dans Tableau 31-5.

Tableau 31-5. Propriétés supplémentaires de configuration des ensembles de DataSource

PropriétéTypeDescription
dataSourceNameStringChaque DataSource de l'ensemble doit avoir un nom unique.
initialConnectionsintLe nombre de connexions à créer sur la base de données à l'initialisation de l'ensemble.
maxConnectionsintLe nombre maximum de connexions ouvertes sur la base de données. Quand plus de connexions sont demandées, l'appelant est bloqué jusqu'une connexion soit disponible dans le pool.

Exemple 31-9 montre un exemple de code d'application typique utilisant un DataSource de l'ensemble.

Exemple 31-9. Exemple de code pour DataSource

Le code pour initialiser un DataSource de l'ensemble pourrait ressembler à ceci :

Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource();
source.setDataSourceName("Une source de données");
source.setServerName("localhost");
source.setDatabaseName("test");
source.setUser("utilisateur_test");
source.setPassword("motdepassetest");
source.setMaxConnections(10);

Puis le code utilisant une connexion du pool pourrait ressembler à ceci. Notez qu'il est indispensable que les connexions soient fermées. Sinon, l'ensemble << manquera >> de connexions et finira par bloquer tous les clients.

Connection con = NULL;
try {
    con = source.getConnection();
    // utilisez la connexion
} catch (SQLException e) {
    // trace de l'erreur
} finally {
    if (con != NULL) {
        try { con.close(); } catch (SQLException e) {}
    }
}

31.10.4. Sources de données et JNDI

Toutes les implémentations de ConnectionPoolDataSource et de DataSource peuvent être enregistrées dans JNDI. Dans le cas d'une implémentation sans pool de connexions, une nouvelle instance est créée à chaque fois que l'objet est récupéré à partir de JNDI avec les mêmes paramètres que ceux de l'instance qui avaient été stockés. Pour les implémentations de pool, la même instance est récupérée aussi longtemps qu'elle sera disponible (c'est-à-dire pas une JVM différent récupérant l'ensemble à partir de JNDI), sinon une nouvelle instance est créée avec les mêmes paramètres.

Dans l'environnement du serveur d'application, habituellement, l'instance de DataSource du serveur d'applications est stockée dans JNDI au lieu de l'implémentation ConnectionPoolDataSource de PostgreSQL.

Dans un environnement applicatif, l'application pourrait stocker le DataSource dans JNDI pour qu'elle n'ait pas besoin de faire une référence au DataSource disponible pour tous les composants de l'application qui pourraient en avoir besoin. Un exemple de ceci est montré dans Exemple 31-10.

Exemple 31-10. Exemple de code pour un DataSource JNDI

Le code de l'application pour initialiser un DataSource de l'ensemble et pour l'ajouter à JNDI pourrait ressembler à ceci :

Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource();
source.setDataSourceName("A Data Source");
source.setServerName("localhost");
source.setDatabaseName("test");
source.setUser("testuser");
source.setPassword("testpassword");
source.setMaxConnections(10);
new InitialContext().rebind("DataSource", source);

Puis, le code pour utiliser la connexion de l'ensemble pourrait ressembler à ceci :

Connection con = NULL;
try {
    DataSource source = (DataSource)new InitialContext().lookup("DataSource");
    con = source.getConnection();
    // utilisez la connexion
} catch (SQLException e) {
    // tracez l'erreur
} catch (NamingException e) {
    // La source de données n'a pas été trouvée dans JNDI
} finally {
    if (con != NULL) {
        try { con.close(); } catch (SQLException e) {}
    }
}