@TransactionManagement
, comme dans l'exemple suivant. Cette annotation ne peut être posée que sur une classe, le comportement d'un EJB vis-à-vis de la gestion des transactions est donc global à un EJB, et ne peut se régler méthode par méthode.
Exemple 68. Annotation sur un EJB en mode bean managed transaction
@Stateless(mappedName="MarinService") @Remote(MarinService.class) @TransactionManagement(TransactionManagementType.BEAN) public class MarinServiceImpl implements MarinService { // reste de la classe }
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.
Exemple 69. Injection d'une transaction dans un EJB
@Stateless(mappedName="MarinService") @Remote(MarinService.class) @TransactionManagement(TransactionManagementType.BEAN) public class MarinServiceImpl implements MarinService { @Resource private UserTransaction transaction ; // reste de la classe }
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.
setTransactionTimeOut(int)
: permet de fixer un temps au bout duquel une transaction doit être annulée.
Connection
, par ses méthodes
commit()
,
rollback()
et éventuellement
setAutoCommit(boolean)
.
Exemple 70. Injection de sources de données et entity manager
@Stateless(mappedName="MarinService") @Remote(MarinService.class) @TransactionManagement(TransactionManagementType.BEAN) public class MarinServiceImpl implements MarinService { @Resource private UserTransaction transaction ; @Resource(mappedName="jdbc/CoursEJBDS") private DataSource dataSource ; @PersistenceContext(unitName="cours-ear-pu") private EntityManager em ; // reste de la classe }
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
.
getStatus()
de l'interface
UserTransaction
renseigne sur l'état courant de cette transaction.