I. Établir une connexion
1. Généralités
Une source de données peut être une DBMS (DataBase Management System) donc dans ce cas elle nécesiste l' API JDBC, ou bin ell peut-être un système de fichiers . Pour se servir de l'API JDBC pour se connecter à une source de données on utilise une des deux classes suivantes:
- DriverManager:
Cette classe permet de connecter une application à une base de données accessible via un URL spécifique. Lorsque cette classe établit une connexion, elle charge automatiquement tous les pilotes "JDBC 4.0" trouvés dans le CLASSPATH. Le chargement des drivers dans le CLASSPATH doit se faire manuellement soit par le développeur de l'application soit l'administrateur système (de préférence utiliser JDBC 4.0 ou plus). - DataSource:
De préférence on utilise cette classe au lieu de DriverManager car elle permet de rendre transparents les détails sur la source de données de l'application; DataSource s'utilise au sein d'un serveur d'application (WildFly, Glassfish, ...).
II. DriverManager
1. DriverManager.getconnection
La classe DriverManager est une classe qui ne contient que des méthodes statiques. Ces méthodes sont des utilitaires qui gèrent l'accès aux bases de données par des applications développées en Java et par les différents drivers JDBC à l’intérieur d'un programme Java; avec cette classe on ne crée ni ne récupère d'objet java.
Pour réaliser une connexion à une base de données on utilise une des méthodes DriverManager.getConnection(...); chacune de ces méthodes retourne un objet d'une classe qui implémente l'interface Connection; elles ont comme premier argument une "URL JDBC" et elles ont besoin des pilotes adaptées pour gérer la connexion à la base repérée par l' URL passée en paramètre.
Une URL JDBC doit commencer par jdbc. Le second argument est le protocole sous-jacent dans lequel le pilote est traduit. Le troisième argument est un identificateur de base de données. La syntaxe d'une URL JDBC est donc:
jdbc:<sous-protocole>:<baseID>
la partie baseID est propre au sous-protocole.
Exemples d'URL JDBC :
pour MySQL on a: " jdbc:mysql://localhost:3306/", où localhost représente le serveur (ici on a un serveur local mais pour un serveur distant on remplace localhost par le nom du serveur distant) et 3306 le port de de communication de la base de données. Pour Java Base de données on a: "jdbc:derby:testdb;create=true", ou "testdb" est le nom de la base de données et "create=true" une instruction qui dit au DBMS de créer la base de données.
Remarques:
Dans l'URL d'une base de données on spécifie également le nom de la base de données à laquelle on souhaite se connecter. Par exemple, l'URL "jdbc:mysql://localhost:3306/mysql" représente l'URL de la base de données MySQL nommée mysql.
Dans les versions précédentes de JDBC 4.1, pour obtenir une connexion, on devait d'abord initialiser le pilote JDBC en appelant la méthode Class.forName("..."). Ces méthodes requéraient un objet de type java.sql.Driver.
Chaque pilote JDBC contient une ou plusieurs classes qui implémente l'interface java.sql.Driver. Les pilotes pour Java DB sont "org.apache.derby.jdbc.EmbeddedDriver" et "org.apache.derby.jdbc.ClientDriver", et celui pour MySQL Connector/J est "com.mysql.jdbc.Driver". Tous les pilotes JDBC 4.0 qui se trouvent dans votre chemin d'accès aux classes sont automatiquement chargés.
2. Spécification de l'URL de de connexions des base de données
Une URL de connexion à une base de données est une chaîne utilisée par votre pilote JDBC SGBD pour se connecter à une base de données. Il peut contenir des informations telles que l'emplacement où rechercher la base de données, le nom de la base de données à se connecter et les propriétés de configuration. La syntaxe exacte d'une URL de connexion à une base de données est spécifiée par votre SGBD. Les lignes ci-dessus montre le syntaxe de l'URL pour se connecter à une base de données une DB Java:
jdbc:derby:[subsubprotocol:][databaseName] [;attribute=value]*
"subsubprotocol" spécifie où Java DB devrait chercher pour la base de données.
- subsubprotocol : Cela peut-être un répertoire, ou en mémoire ou dans la CLASSPATH ou dans un fichier jar.
- databaseName : is the name of the database to connect to.
- attribute=value : represents an optional, semicolon-separated list of attributes. These attributes enable you to instruct Java DB to perform various tasks, including the following:
- Créer la base de données spécifiée dans l'URL de connexion.
- Encrypter la base de données dans l'URL de connexion .
- Spécifie les répertoire à sauvegarder le "loggin" et tracer les informations
- Spécifie un nom d'utilisateur et un mot de passe permettant de se connecter à la base de données.
L'URL Connector/J de la base de données MySQL
Les lignes ci-dessus montre le syntaxe de l'URL pour se connecter à une base de données MySQL:
jdbc:mysql://[host][,failoverhost...] [:port]/[database] [?propertyName1][=propertyValue1] [&propertyName2][=propertyValue2]...
"host:port" c'est le nom du serveur hôte et le port de communication de la base de données MySQL. si rien 'est précisé on aura par défaut le serveur hôte est "127.0.0.1" et le port 3306.
"database" c'est le nom de la base de données à laquelle on va se connecter. Si ce nom n'est précisé la connexion ne se fera pas.
"failover" c'est le nom d'une base de données de secours (MySQL Connector/J supports failover).
"propertyName=propertyValue" ceci représente une liste de propriétés optionnelles; ces propriétés permettent de préciser au driver "Connector/J" de MySQL d'exécuter certaines taches.
III. Connexion à des objets DataSource
1. Généralités
Les objets DataSource permettent d'avoir un pool de connexions et des transactions distribuées. Ces fonctionnalités sont essentielles particulièrement pour les EJB dont elles en font partie. Dans la suite on va montrer comment un administrateur système configure l'environnement afin que les programmeurs puissent utiliser un objet DataSource pour obtenir des connexions.
2. Utilisation d'objets DataSource pour se connecter
Les objets instanciés par les classes qui implémentent DataSource représentent un SGBD particulier (DataBase Management System) ou une autre source de données, comme un fichier. Si on se trouve dans une situation où on veut utiliser différentes sources de données, on doit déployer des objets DataSources différents , chaque source de données ayant son objet DataSource. Chaque objet DataSource peut être déployé suivant une des trois méthodes suivantes:
- A basic DataSource implementation produces standard Connection objects that are not pooled or used in a distributed transaction.
- A DataSource implementation that supports connection pooling produces Connection objects that participate in connection pooling, that is, connections that can be recycled.
- A DataSource implementation that supports distributed transactions produces Connection objects that can be used in a distributed transaction, that is, a transaction that accesses two or more DBMS servers.
Chaque driver JDBC doit avoir une classe qui implémente l'interface DataSource basique; pour le driver JDBC de Java c'est "org.apache.derby.jdbc.ClientDataSource" et pour MySQL, "com.mysql.jdbc.jdbc2.optional.MysqlDataSource".
3. Déploiement d'objets DataSource basiques
Si on travaille avec la classe DataSource, l'administrateur du système sur lequel on travaille doit déployer des objets DataSource pour que l'équipe de programmation du projet puisse s'en servir. Deployer un objet DataSource consiste à faire les trois tâches suivantes:
- Créer une instance de la classe qui implémente l'interface DataSource
- Fixer la valeur de chacune des propriétés de l'objet DataSource
- Enregistrer cette instance à un service de nommage qui utilise l'API JNDI
L'implémentation basique de DataSource ne supporte pas l'utilisation de pool de connections ou de transaction distribuée; cela est équivalent à l'utilisation de DriverManger.
Créer une instance de la classe DataSource et fixer les valeurs de ses propiétés
Si on veut implémenter une instance de la classe DataSource basique, celle-ci doit être de la forme "com.dbaccess.BasicDataSource" et implémenter l'interface DataSource. Une fois qu'on ait cette classe qui implémente l'interface DataSoource, on fixe les valeurs des différentes propriétés de cette classe comme suit
com.dbaccess.BasicDataSource ds = new com.dbaccess.BasicDataSource(); ds.setServerName("nomServeur"); ds.setDatabaseName("CUSTOMER_ACCOUNTS"); ds.setDescription("Customer accounts database for billing");
La variable ds représente la base de données installée sur le serveur "nomServeur" et toute connexion produite par l'objet ds instance de la classe BasicDataSource sera associée à la base de données CUSTOMER_ACCOUNTS. Illustrons notre propos avec la base de données MySQL dans l'exemple ci-dessous:
Exemple avec MySQL
/*
* MySqlDataSource.java */ import java.sql.*; import javax.sql.*; public class MySqlDataSource { public static void main(String [] args) { Connection con = null; try { // Setting up the DataSource object com.mysql.jdbc.jdbc2.optional.MysqlDataSource ds = new com.mysql.jdbc.jdbc2.optional.MysqlDataSource(); ds.setServerName("localhost"); ds.setPortNumber(3306); ds.setDatabaseName("NomDB"); ds.setUser("utilisateur"); ds.setPassword("motDePasse"); // Getting a connection object con = ds.getConnection(); // Getting database info DatabaseMetaData meta = con.getMetaData(); System.out.println("Server name: " + meta.getDatabaseProductName()); System.out.println("Server version: " + meta.getDatabaseProductVersion()); // Closing the connection con.close(); } catch (Exception e) { System.err.println("Exception: "+e.getMessage()); } } }
Dans l'exemple ci-dessus penser à mettre "mysql-connector-java-5.1.36-bin.jar" dans le "CLASSPATH".
Enregistrement d'objet DataSource
Une fois les valeurs de l'objet DataSource fixées, l'administrateur système peut enregistrer l'objet BasicDataSource (MysqlDataSource pour MySQL) dans le service de nommage utilisant l' API JNDI. le bout de code ci-dessous illustre enregistrement de l'objet BasicDataSource et son association au nom logique jdbc/billingDB:
Context ctx = new InitialContext(); ctx.bind("jdbc/billingDB", ds);
La première ligne du code crée un objet instance de la classe InitialContext et c'est le premier point d'entrée dans le service de nommage. A la deuxième ligne, on associe l'objet ds instance de la classe BasicDataSource au nom logique jdbc/billingDB. Ce nom logique sera utilisé par le service de nommage; à chaque fois qu'on évoquera ce nom le service de nommage retournera un objet de type BasicDataSource. BilingDB est le nom logique donné à l'objet ds instance de la classe BasicDataSource.
Utilisation de l'objet DataSource deployé
Une fois qu'une implémentation de DataSource basique a été déployée par un administrateur système, les développeurs peuvent s'en servir. Cela signifie qu'un programmeur peut donner le nom de source de données logique qui était lié à une instance d'une classe DataSource et le service de dénomination JNDI renverra une instance de cette classe DataSource. La méthode getConnection peut ensuite être appelée sur cet objet DataSource pour obtenir une connexion à la source de données qu'il représente. Par exemple, un programmeur peut écrire les deux lignes de code suivantes pour obtenir un objet DataSource qui produit une connexion à la base de données CUSTOMER_ACCOUNTS:
Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("jdbc/billingDB");
La première ligne de code obtient un contexte initial comme point de départ pour récupérer un objet DataSource. Lorsqu'on donne le nom logique" jdbc/billingDB" à la méthode "lookup", la méthode renvoie l'objet DataSource lié à jdbc/billingDB au moment du déploiement. Étant donné que la valeur de retour de la méthode "lookup" est un objet Java, on doit le caster pour un type d'objet DataSource spécifique avant de l'affecter à la variable ds.
La variable ds est une instance de la classe com.dbaccess.BasicDataSource qui implémente l'interface DataSource. L'appel de la méthode ds.getConnection donne une connexion à la base de données CUSTOMER_ACCOUNTS
Connection con = ds.getConnection("fernanda","brewed");
La méthode getConnection a comme paramètre d'appel le nom d'utilisateur et le mot de passe car la variable ds contient le reste des informations nécessaires à l'établissement d'une connexion avec la base de données CUSTOMER_ACCOUNTS.
En raison de ses propriétés, un objet DataSource est une meilleure alternative que la classe DriverManager pour obtenir une connexion. Avec un objet DataSource n'ont pas besoin de coder le nom du pilote oude l'URL JDBC dans leurs applications, ce qui les rend plus portables. En outre, les propriétés DataSource rendent le code de maintenance beaucoup plus simple. En cas de modification, l'administrateur système peut mettre à jour les propriétés de la source de données et ne pas se préoccuper de changer chaque application qui établit une connexion à la source de données. Par exemple, si la source de données a été déplacée vers un serveur différent, tout l'administrateur système aurait à faire est de définir la propriété serverName au nouveau nom de serveur.
Outre la portabilité et la facilité de maintenance, l'utilisation d'un objet DataSource pour obtenir des connexions peut offrir d'autres avantages. Lorsque l'interface DataSource est implémentée pour fonctionner avec une implémentation ConnectionPoolDataSource, toutes les connexions produites par les instances de cette classe DataSource seront automatiquement mises en pool. De même, lorsque l'implémentation DataSource est implémentée pour fonctionner avec une classe XADataSource, toutes les connexions qu'il produit seront automatiquement des connexions qui peuvent être utilisées dans une transaction distribuée. La section suivante montre comment déployer ces types de mises en œuvre DataSource
4. Déploiement d'autres implémentations de DataSource
Un objet DataSource non basique produit un pool de connexions. On commence d'abord par déployer un objet ConnectionPoolDataSource, puis déploie un objet DataSource pour fonctionner avec. Les propriétés de l'objet ConnectionPoolDataSource sont définies de sorte qu'elles représentent la source de données à laquelle les connexions seront produites. Après que l'objet ConnectionPoolDataSource soit enregistré à un service de nommage JNDI, on déploie l'objet DataSource. Généralement, seules deux propriétés de l'objet DataSource seront fixées: "description" et "dataSourceName".
Avec les objets ConnectionPoolDataSource et DataSource déployés, on peut peut appeler la méthode DataSource.getConnection sur l'objet DataSource et obtenir un pool de connexion.
Considérons un cas où on a besoin d'un pool de connexions; l'administrateur du système doit déployer sur le serveur tous les éléments nécessaires , à savoir un JDBC qui fournira :
- une classe qui implémente l'interface ConnectionPoolDataSource; chaque instance de cette classe agit comme une fabrique (Factory) de connexions et créera des objets PooledConnection ; l'instance de cette classe sera créée en premier et les valeurs de ses propriétées seront fixées; ensuite elle est enregistrée à un service de nommage JNDI comme on le voit dans le code ci-dessous:
com.dbaccess.ConnectionPoolDS cpds = new com.dbaccess.ConnectionPoolDS(); cpds.setServerName("creamer"); cpds.setDatabaseName("COFFEEBREAK"); cpds.setPortNumber(9040); cpds.setDescription("Connection pooling for " + "COFFEEBREAK DBMS"); Context ctx = new InitialContext(); ctx.bind("jdbc/pool/fastCoffeeDB", cpds);
- une classe qui implémente l'interface DataSource; cette classe interagit avec la variable cpds et les autres instances de la classe "com.dbaccess.ConnectionPoolDS" déployée (voir ci-dessus). Seules deux propriétés de cette instance sont définies; La propriété "description" toujours requise, et l'autre propriété, dataSourceName; cette dernière donne le nom logique JNDI pour cpds qui est une instance de la classe com.dbaccess.ConnectionPoolDS. En d'autres termes, cpds représente l'objet ConnectionPoolDataSource qui implémentera le regroupement de connexions pour l'objet DataSource...Le code suivant, qui serait probablement exécuté par un outil de déploiement, crée un objet PooledDataSource, définit ses propriétés et le lie au nom logique "jdbc/fastCoffeeDB":
com.applogic.PooledDataSource ds = new com.applogic.PooledDataSource(); ds.setDescription("produces pooled connections to COFFEEBREAK"); ds.setDataSourceName("jdbc/pool/fastCoffeeDB"); Context ctx = new InitialContext(); ctx.bind("jdbc/fastCoffeeDB", ds);
A partir de là un objet DataSource est déployé et une quelconque application peut travailler avec un pool de connexion avec la base de données.
- .....
5. Récupérer et utiliser des pools de Connexion
Un pool de connexions est un ensemble d' instances de la classe Connection qui sont en cache; ces objets représentent des connexions physiques à la base de données et à chaque fois une application peut s'en servir pour se connecter à la base de données. A l'exécution, si l'application nécessite une connexion à la base de données elle sollicite le pool de connexions présentes en cache; si le nombre de pool de connexions au sein du pool sont épuisé, l'application en crée une automatiquement. Toute connexion non utilisée par l'application est retournée dans le pool et ainsi elle est disponible pour une nouvelle utilisation.
Les pools de connexions favorisent la réutilisation des objets Connexion et réduisent le nombre de fois où des objets de connexion sont créés. Les pools de connexions améliorent considérablement les performances des applications qui sollicitent beaucoup la bases de données, car la création d'objets de connexion à la base de données est coûteuse en temps et ressources.
Une fois que ces objets DataSource et ConnectionPoolDataSource sont déployés, un développeur peut utiliser l'objet DataSource pour obtenir un pool de connexion. Le code pour obtenir un pool de connexions est exactement identique au code pour obtenir une connexion sans pool de connexions, comme indiqué dans les deux lignes suivantes:
ctx = new InitialContext(); ds = (DataSource)ctx.lookup("jdbc/fastCoffeeDB");
La variable ds représente un objet DataSource qui produit des pools connexions à la base de données COFFEEBREAK. On ne récupére cet objet DataSource qu'une seule fois car on peut l'utiliser pour produire autant de pool de connexions que nécessaire. Appeler la méthode getConnection sur la variable ds produit automatiquement un pool de connexions car l'objet DataSource que représente la variable ds a été configuré pour produire des pools de connexions. La mise en commun des connexions est transparente pour le développeur. Il n'y a que deux choses qu'on doit faire lorsqu'on utilise une pool de connexions :
- Utilisez un objet DataSource plutôt que la classe DriverManager pour obtenir la connexion. Dans la ligne de code suivante, ds est un objet DataSource implémenté et déployé de telle sorte qu'il crée des connexions mises en pool ; les paramètres "username" et "password" sont des variables qui représentent les informations d'identification de l'utilisateur qui a accès à la base de données:
Connection con = ds.getConnection(username,password);
- Utilisez une instruction finally pour fermer un pool de connexions. Pour cela on se sert du bloc finally suivant le bloc try/catch s'applique au code dans lequel le pool de connexions a été utilisée:
.... try { Connection con = ds.getConnection(username, password); // ... code to use the pooled // connection con } catch (Exception ex { // ... code to handle exceptions } finally { if (con != null) con.close(); }
Sinon, une application utilisant un pool de connexions est identique à une application utilisant une connexion classique. La seule autre chose qu'un développeur d'application peut remarquer lorsqu'on utilise un pool de connexions c'est la performance qui est nettement meilleure.
L'exemple de code suivant obtient un objet DataSource qui produit des connexions à la base de données COFFEEBREAK et l'utilise pour mettre à jour un prix dans la table COFFEES:
import java.sql.*; import javax.sql.*; import javax.ejb.*; import javax.naming.*; public class ConnectionPoolingBean implements SessionBean { // ... public void ejbCreate() throws CreateException { ctx = new InitialContext(); ds = (DataSource)ctx.lookup("jdbc/fastCoffeeDB"); } public void updatePrice(float price, String cofName, String username, String password) throws SQLException{ Connection con; PreparedStatement pstmt; try { con = ds.getConnection(username, password); con.setAutoCommit(false); pstmt = con.prepareStatement("UPDATE COFFEES " + "SET PRICE = ? " + "WHERE COF_NAME = ?"); pstmt.setFloat(1, price); pstmt.setString(2, cofName); pstmt.executeUpdate(); con.commit(); pstmt.close(); } finally { if (con != null) con.close(); } } private DataSource ds = null; private Context ctx = null; }
Il faut noter qu'en tout point le code ci-dessus n'est pas différent du code utilisé pour une connexion classique (sans utiliser un pool de connexion) sauf à certains point comme, l'utilisation des imports "javax.sql, javax.ejb" et "javax.naming" en plus de java.sql . Les interfaces DataSource et ConnectionPoolDataSource sont inclus dans le package javax.sql et le constructeur JNDI "InitialContext", la méthode "Context.lookup" font partie du package javax.naming.
6.1 Déploiement de transactions distribuées
Les objets DataSource peuvent être déployés pour obtenir des connexions pour des transactions distribuées. Comme pour le pool de connexions, deux instances de classe différentes doivent être déployées et être implémentées: un objet XADataSource et un objet DataSource.
Supposons que le serveur d'EJB inclut la classe "DataSource com.applogic.TransactionalDS", et qu'il fonctionne avec une classe "XADataSource" telle que "com.dbaccess.XATransactionalDS". Le fait qu'il fonctionne avec n'importe quelle classe XADataSource rend le serveur EJB portable sur les pilotes JDBC. Lorsque les objets DataSource et XADataSource sont déployés, les connexions produites peuvent participer à des transactions distribuées. Dans ce cas, la classe "com.applogic.TransactionalDS" est implémentée de telle sorte que les connexions fasse partie de pool de connexions, ce qui est aussi le cas pour les classes DataSource fournies pour le serveur d'EJB.
Il faut toujours se souvenir qu' doit d'abord déployer l'objet XADataSource ; le code suivant crée une instance de com.dbaccess.XATransactionalDS et définit ses propriétés:
com.dbaccess.XATransactionalDS xads = new com.dbaccess.XATransactionalDS(); xads.setServerName("creamer"); xads.setDatabaseName("COFFEEBREAK"); xads.setPortNumber(9040); xads.setDescription("Distributed transactions for COFFEEBREAK DBMS");
Le code suivant enregistre l'objet "com.dbaccess.XATransactionalDS" xads à un service de nommage JNDI et le nom logique associé à xads a le sous-contexte xa ajouté sous jdbc. Oracle recommande que le nom logique de toute instance de la classe "com.dbaccess.XATransactionalDS" commence toujours par " jdbc/xa".
Context ctx = new InitialContext(); ctx.bind("jdbc/xa/distCoffeeDB", xads);
Ensuite, l'objet DataSource implémenté pour interagir avec des xads et d'autres objets XADataSource est déployé. Notez que la classe DataSource, com.applogic.TransactionalDS, peut fonctionner avec une classe XADataSource à partir de n'importe quel fournisseur de pilote JDBC. Le déploiement de l'objet DataSource implique la création d'une instance de la classe com.applogic.TransactionalDS et la définition de ses propriétés. La propriété dataSourceName est définie sur jdbc/xa/distCoffeeDB, le nom logique associé à com.dbaccess.XATransactionalDS. Il s'agit de la classe XADataSource qui implémente la capacité de transaction distribuée pour la classe DataSource. Le code suivant déploie une instance de la classe DataSource:
com.applogic.TransactionalDS ds = new com.applogic.TransactionalDS(); ds.setDescription("Produces distributed transaction " + "connections to COFFEEBREAK"); ds.setDataSourceName("jdbc/xa/distCoffeeDB"); Context ctx = new InitialContext(); ctx.bind("jdbc/distCoffeeDB", ds);
Maintenant que les instances des classes com.applogic.TransactionalDS et com.dbaccess.XATransactionalDS ont été déployées, une application peut appeler la méthode getConnection sur les instances de la classe TransactionalDS pour obtenir une connexion à la base de données COFFEEBREAK pouvant être utilisée dans les transactions distribuées
7. Utiliser des Connexions pour des transactions distribuées
Pour obtenir une connexion pouvant être utilisée pour des transactions distribuées, on doit utiliser un objet DataSource correctement implémenté et déployé. Avec un tel objet DataSource, appelez la méthode getConnection dessus. Une fois la connexion établie, on l'utilise comme comme les autres type de connexion vues précéddemment. Étant donné que jdbc/distCoffeesDB a été associé à un objet XADataSource à un service de nommage JNDI, le code suivant produit un objet Connection qui est utilisable comme transactions distribuées:
Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("jdbc/distCoffeesDB"); Connection con = ds.getConnection();
Il existe quelques restrictions mineures mais importantes sur la façon dont cette connexion est utilisée alors qu'elle fait partie d'une transaction distribuée. Un gestionnaire de transactions contrôle lorsqu'une transaction distribuée commence et quand elle est faite ou annulée; Par conséquent, le code d'application ne devrait jamais appeler les méthodes Connection.commit ou Connection.rollback. Une application ne devrait également pas appeler Connection.setAutoCommit (true), ce qui permet le mode auto-commit, car cela interférerait également avec le contrôle du gestionnaire de transactions des limites de transaction. Cela explique pourquoi une nouvelle connexion créée dans le cadre d'une transaction distribuée a son mode d'auto-validation désactivé par défaut.
Pour l'exemple suivant, supposons qu'un ordre de café a été expédié, ce qui déclenche des mises à jour sur deux tables qui résident sur des serveurs de SGBD différents. La première table est une nouvelle table INVENTORY, et la seconde est la table COFFEES. Étant donné que ces tables sont sur des serveurs de SGBD différents, une transaction impliquant les deux sera une transaction distribuée. Le code dans l'exemple suivant obtient une connexion, met à jour la table COFFEES et ferme la connexion, est la deuxième partie d'une transaction distribuée.
Notez que le code ne confirme pas explicitement ou renvoie les mises à jour car la portée de la transaction distribuée est contrôlée par l'infrastructure système sous-jacente du serveur intermédiaire. En outre, en supposant que la connexion utilisée pour la transaction distribuée est une connexion groupée, l'application utilise un bloc finally pour fermer la connexion. Cela garantit qu'une connexion valide sera fermée même si une exception est déclenchée, assurant ainsi que la connexion est renvoyée au pool de connexion pour être recyclé.
L'exemple de code suivant illustre un Bean d'entreprise, qui est une classe qui implémente les méthodes qui peuvent être appelées par un ordinateur client. Le but de cet exemple est de démontrer que le code d'application pour une transaction distribuée n'est pas différent de l'autre code, sauf qu'il n'appelle pas les méthodes de connexion commit, rollback ou setAutoCommit (true).
import java.sql.*; import javax.sql.*; import javax.ejb.*; import javax.naming.*; public class DistributedTransactionBean implements SessionBean { // ... public void ejbCreate() throws CreateException { ctx = new InitialContext(); ds = (DataSource)ctx.lookup("jdbc/distCoffeesDB"); } public void updateTotal(int incr, String cofName, String username, String password) throws SQLException { Connection con; PreparedStatement pstmt; try { con = ds.getConnection(username, password); pstmt = con.prepareStatement("UPDATE COFFEES " + "SET TOTAL = TOTAL + ? " + "WHERE COF_NAME = ?"); pstmt.setInt(1, incr); pstmt.setString(2, cofName); pstmt.executeUpdate(); stmt.close(); } finally { if (con != null) con.close(); } } private DataSource ds = null; private Context ctx = null; }
...