Dans le contexte application managed transactions les transactions sont gérées manuellement, comme si l'on était dans une application JSE. La seule différence est que, pour obtenir une transaction, l'on s'adresse tout de même au serveur d'applications.

Une transaction est dans ce cas modélisée par l'interface UserTransaction. On peut récupérer cette transaction de deux manières : soit par injection de dépendances, soit en demandant cette transaction à l'annuaire du serveur. L'injection de dépendance est la manière la plus simple, que l'on montre sur l'exemple suivant.

Enfin, rappelons que l'injection d'une transaction ne peut se faire que dans un EJB qui gère lui-même ses transactions, donc annoté avec @TransactionManagement(TransactionManagementType.BEAN). Dans le cas où les transactions sont gérées par le conteneur d'EJB, cette injection est illégale, et peut mener à une erreur de démarrage de l'application.


L'interface UserTransaction propose les six méthodes suivantes.

  • begin() : marque le début d'une transaction.

  • commit() : marque la fin d'une transaction, et demande sa validation. Cette validation peut échouer en jetant une exception.

  • rollback() : marque la fin d'une transaction en demandant l'annulation de toutes les opérations effectuées dans le contexte de cette transaction. Cette annulation peut également échouer en jetant une exception.

  • setRollbackOnly() : impose que la transaction soit annulée en fin d'exécution. Si un appel à commit() est fait, alors une exception sera générée et la transaction sera annulée.

  • getStatus() : retourne le statut de la transaction. Ce statut est un entier dont les valeurs sont fixées par l'interface javax.transaction.Status. Il y a dix statuts possibles pour une transaction :

    • STATUS_ACTIVE : indique que la transaction est en cours, et qu'elle n'a pas été marquée pour être annulée ;

    • STATUS_COMMITTED : la transaction a été validée ;

    • STATUS_COMMITTING : le processus de validation est en cours, donc un appel à la méthode commit() a été fait, mais il n'est pas terminé ;

    • STATUS_MARKED_ROLLBACK : la transaction a été marquée pour être annulée, en principe par un appel à la méthode setRollbackOnly() ;

    • STATUS_NO_TRANSACTION : la transaction n'existe plus ;

    • STATUS_PREPARED : la transaction est prête à être validée, ce qui indique que tous les éléments qui participent à cette transaction (par exemple les différentes bases de données) sont prêts pour la validation finale ;

    • STATUS_PREPARING : la transaction est en train de consulter les éléments qui participent, qui n'ont pas encore répondu s'ils étaient prêts ou non pour la validation finale ;

    • STATUS_ROLLEDBACK : la transaction a été annulée ;

    • STATUS_ROLLING_BACK : la transaction est en cours d'annulation ;

    • STATUS_UNKNOWN : l'état courant de la transaction n'est pas connu, ce qui indique qu'elle en train de passer d'un état à l'autre.

    Il peut être utile, pour un EJB avec état, d'interroger la transaction pour connaître l'état dans lequel elle se trouve. Effectivement, un tel EJB peut démarrer une transaction lors d'un appel de méthode, et la fermer lors d'un autre, avec encore d'autres appels de méthodes entre ce premier et ce dernier.

  • setTransactionTimeOut(int) : permet de fixer un temps au bout duquel une transaction doit être annulée.

Dans un scénario JDBC classique, les choses se déroulent de la façon suivante :

  • une application cliente ouvre une connexion sur une base de données ;

  • la transaction est gérée au travers de l'objet Connection, par ses méthodes commit(), rollback() et éventuellement setAutoCommit(boolean).

Un EJB n'ouvre pas une connexion sur une base de données de cette manière. Il le fait par injection de dépendances :

  • d'une source de données s'il a besoin d'émettre des ordres SQL directement sur la base, ou s'il n'utilise pas JPA ;

  • d'une unité de persistance s'il utilise JPA, qui elle-même référence une source de données par son nom.

Un EJB peut bien sûr utiliser autant de connexions sur autant de bases de données qu'il veut, soit directement soit au travers de JPA.

Ensuite, il obtient une référence sur une transaction également par injection de dépendances, comme nous l'avons vu. Résumons tout ceci sur l'exemple suivant.


Cet objet de types DataSource permet de récupérer une connexion JDBC à une base de données en appelant sa méthode getConnection().

Se pose alors la question du lien entre la transaction obtenue, et les différentes opérations menées à bien au travers des différentes connexions JDBC, utilisées directement ou non.

La réponse est fournie par la spécification EJB. Toute opération sur une base de données effectuée dans une méthode métier d'un EJB, après un appel à transaction.begin() est faite dans le contexte de cette transaction. Tous les principes de fonctionnement des transactions s'appliquent, en particulier l'atomicité et la cohérence.

Le cas où l'on s'adresse à plusieurs bases de données différentes est ici nouveau, et pose le problème de la synchronisation des opérations. Cette synchronisation est résolue en procédant en deux temps, on appelle cette procédure le two phases commit .

  • Lors d'une première étape le serveur d'application interroge les différentes bases de données, qui indiquent qu'elles sont prêtes à valider les éléments qui les concernent ou pas.

  • Une fois que tous les éléments ont répondu par l'affirmative, alors la validation finale est faite, et toutes les bases valident leurs travail. Bien sûr, si l'une des bases n'était pas prête à faire cette validation, c'est l'ensemble du processus qui est annulé, respectant en cela le principe d'atomicité.

JPA & EJB
Retour au blog Java le soir
Cours & Tutoriaux

Table des matières

Introduction
1. Objet du mapping objet / relationnel
2. Un peu d'histoire
Un premier exemple
1. Introduction
2. Création de l'environnement technique
2.1. Introduction
2.2. Création de la base Derby
2.3. Création du projet NetBeans et d'une première entité
2.4. Structure d'un projet persistant
2.5. Une première classe persistante
2.6. Un premier fichier persistence.xml
3. Utilisation de ce premier exemple
3.1. Écriture du code d'utilisation
3.2. Exécution de notre premier exemple
3.3. Modification de la class Marin
3.4. Opérations CRUD
Mettre un jeu de classes en base
1. Introduction
2. Définition d'une entité JPA
2.1. Écriture de l'entité
2.2. Annotation de l'entité
2.3. Annotations des champs
2.4. Exemple d'utilisation
3. Opérations sur les entités
3.1. Introduction
3.2. Opération PERSIST
3.3. Opération REMOVE
3.4. Opération REFRESH
3.5. Opération DETACH
3.6. Opération MERGE
4. Mise en relation d'entités
4.1. Introduction
4.2. Relations unidirectionnelles et bidirectionnelles
4.3. Relation 1:1
4.4. Relation 1:p
4.5. Relation p:1
4.6. Relation n:p
4.7. Comportement cascade
4.8. Effacement des entités orphelines
5. Charger des entités et leurs relations
6. Objets inclus
6.1. Introduction
6.2. Déclaration d'un objet inclus
6.3. Utilisation d'objets inclus
6.4. Cas où l'objet inclus est nul
6.5. Renommer les colonnes incluses
6.6. Collections d'objets inclus
L'API Collection en base
1. Introduction
2. Enregistrer une collection d'entités
2.1. Enregistrement d'une collection simple
2.2. Enregistrement d'un Set
2.3. Enregistrement d'une List
3. Enregistrer une collection de types de base
4. Enregistrement d'une Map
4.1. Table de hachage de type (type de base, entité)
4.2. Cas où la clé est un champ de la valeur
4.3. Cas d'une table (entité, entité)
Héritage
1. Introduction
2. Enregistrement d'une hiérarchie de classes
2.1. Entité et super-classe non enregistrée
2.2. Position du problème
2.3. Trois façons de faire
3. Stratégie SINGLE_TABLE
3.1. Fonctionnement
3.2. Mise en place
3.3. Limitations
4. Stratégie JOINED
4.1. Fonctionnement
4.2. Mise en place
4.3. Limitations
5. Stratégie TABLE_PER_CLASS
5.1. Fonctionnement
5.2. Mise en place
5.3. Limitations
Requêtes
1. Introduction
2. Un premier exemple
2.1. Écriture d'une première requête
2.2. Exécution d'une première requête
2.3. Exécution d'une première requête d'agrégation
3. Définition de requêtes
3.1. Requêtes dynamiques
3.2. Requêtes paramétrées
3.3. Requêtes nommées
3.4. Requêtes natives
4. Exécution, analyse du résultat
4.1. Exécution d'une requête dynamique
4.2. Exécution d'une requête nommée
4.3. Analyse du résultat
4.4. Cas des résultats de grande taille
4.5. Remarques
5. Clause From
5.1. Définition des entités
5.2. Jointures dans la clause From
5.3. Remarque finale sur les jointures en JPQL
6. Clause Where
6.1. Variables et chemins dans une clause where
6.2. Expressions conditionnelles et opérateurs
6.3. Requêtes imbriquées
6.4. Opérateurs any, all et some
6.5. Expressions fonctionnelles
7. Clauses Group By et Having
8. Opérations Update et Delete
EJB
1. Introduction
2. Un premier exemple
2.1. Introduction
2.2. Installation dans Glassfish à l'aide de Netbeans
2.3. Création d'un premier EJB
2.4. Déploiement de notre premier EJB
2.5. Création d'un client
3. Mise en oeuvre du pattern session facade
3.1. Introduction
3.2. Modèle objet
3.3. Définition de l'unité de persistance
3.4. Assemblage de notre application
3.5. Assemblage et déploiement
3.6. Utilisation du client
4. Opération de persistance en façade
4.1. Introduction
4.2. Enrichissement du service
4.3. Création de la méthode findMarinById(long)
4.4. Ajout de la méthode findAllMarins()
4.5. Utilisation dans un code client
5. Types d'EJB
5.1. Introduction
5.2. Qu'est-ce qu'un EJB ?
5.3. Écriture d'un EJB session
5.4. Qu'est-ce qu'une méthode métier ?
5.5. EJB avec ou sans état
5.6. Gestion des transactions
5.7. Restrictions
6. Cycle de vie d'un EJB
6.1. Cas des EJB sans état
6.2. Cas des EJB avec état
6.3. Injection de dépendances
7. Transaction gérée par l'EJB
7.1. Introduction
7.2. Déclaration du mode transactionnel
7.3. Gestion de la transaction
7.4. Fonctionnement de la transaction
7.5. Cas des EJB avec état
8. Transaction gérée par le serveur
8.1. Introduction
8.2. Déclaration du mode transactionnel
8.3. Gestion de la transaction
8.4. Fonctionnement de la transaction
8.5. Remarques
9. Intercepteurs
9.1. Introduction
9.2. Aperçu général
9.3. Cycle de vie d'un intercepteur
9.4. Object InvocationContext
9.5. Interception d'un EJB ou d'une méthode métier
9.6. Exemple de mise en œuvre d'un intercepteur