Vous êtes sur la page 1sur 59

Gestion des transactions

Michel Buffa (buffa@unice.fr), UNSA 2002


modifi par Richard Grin (version 1.0, 22/11/11)
Gestion de transactions
Service cl pour le dveloppement ct serveur,
Permet des applications de fonctionner de manire
robuste,
Les transactions sont trs utiles lorsqu'on effectue des
oprations de persistance, comme des mises--jours
dans une base de donnes
Dans ce chapitre nous prsentons le concept de
transaction et sa mise en application au sein des EJB.

Motivation pour les transactions
Oprations atomiques, bien que composes de
plusieurs petites oprations
Ex : transfert de compte compte bancaire : on
enlve sur un compte, on dpose sur l'autre
Si une des deux oprations choue, perte de
cohrence !
On veut que soit les deux oprations russissent,
mais si une d'elles choue, on annule le tout et on
remet les comptes dans l'tat initial !
On dit que les deux oprations forment une seule et
mme transaction !

Traitement par exceptions
On peut s'en sortir en grant des exceptions
try {
// retirer de l'argent du compte 1
} catch (Exception e){
// Si une erreur est apparue, on arrte.
return;
}
try {
// Sinon, on dpose l'argent sur le compte 2
} catch (Exception e){
// Si une erreur est apparue, o s'arrte, mais avant, on redpose
//l'argent sur le compte 1
return;
}
Qu'en pensez-vous ?
Traitement par exceptions
Et si on choue la dernire opration et qu'on
narrive pas remettre l'argent sur le compte 1 ?
Et si au lieu d'un traitement simple on a un gros
traitement faire qui se compose de 20
oprations diffrentes ?
Comment on teste tous les cas d'erreur ?
Panne rseau ou panne machine
Le rseau plante, le client reoit une RMI
Remote Exception
L'erreur est intervenue avant qu'on enlve
l'argent, ou aprs ?
Impossible de savoir
Peut-tre que le SGBD s'est crash ? La
machine ? La BD est peut-tre devenue
inconsistante ?
Le traitement par Exception est vraiment
inacceptable ici, il n'est pas suffisant !

Partage concurrent de donnes

Partage concurrent de donnes
Plusieurs clients consultent et modifient les
mmes donnes
On ne peut tolrer de perte d'intgrit des
donnes !
Problmes rsolus par les transactions !
Un transaction est une srie d'oprations qui
apparaissent sous la forme d'une large
opration atomique.
Soit la transaction russit, soit elle choue.
Traduire par "toutes les oprations qui la
composent"
Les transactions s'accordent avec les pannes
machines ou rseau,
Rpondent au problmes du partage de
donnes.
Un peu de vocabulaire
Objet ou composant transactionel
Un composant bancaire impliqu dans une transaction. Un
EJB compte bancaire, un composant .NET, CORBA
Gestionnaire de transaction
Celui qui en coulisse gre l'tat de la transaction
Ressource
L'endroit o on lit et crit les donnes : un DB, une queue de
messages, autre
Gestionnaire de ressource
Driver d'accs une BD, une queue de message
Implmentent l'interface X/Open XA, standard de facto pour la
gestion de transactions
Les proprits ACID
Atomicit
Nombreux acteurs qui votent pour indiquer si la transaction
s'est bien passe ( commit 2 phases )
Consistance
Le systme demeure consistant aprs l'excution d'une
transaction (comptes bancaires ok!)
Isolation
Empche les transactions concurrentes de voir des rsultats
partiels. Chaque transaction est isole des autres.
Implment par des protocoles de synchronisation bas-niveau
sur les BDs
Durabilit
Garantit que les mises jour sur une BD peuvent survivre un
crash (BD, machine, rseau)
En gnral, on utilise un fichier de log qui permet de revenir
dans l'tat avant le crash.
Modles de transactions
Il existe deux modles
1. Flat transactions ou transactions plat
Supportes par les EJBs
2. Nested transactions ou transactions
imbriques
Non supportes par les EJBs pour le moment
Flat transactions
Modle le plus simple.
Aprs qu'une transaction ait dmarr, on effectue des
oprations
Si toutes les oprations sont ok, la transaction est
valide (commited), sinon elle choue (aborted)
En cas de commit, les oprations sont valides
(permanent changes)
En cas d'abort, les oprations sont annules (rolled
back). L'application est galement prvenue
Transactions imbriques
Cas d'cole : on veut faire un tour du monde
1. Notre application achte un billet de train de Nice
Marseille,
2. Puis un billet d'avion de Marseille Londres,
3. Puis un billet d'avion de Londres New-York,
4. L'application s'aperoit qu'il n'y a plus de billet
d'avion disponible ce jour-l pour New-York
Tout choue et on annule toutes les
rservations !
Transactions imbriques
Avec un modle de transactions imbrique,
une transaction peut inclure une autre
transaction,
Si on ne trouve pas de vol pour New-York, on
essaiera peut-tre de prendre une
correspondance par Philadelphie
Gestion des transactions avec les EJBs
Seul le modle flat est support.
Le code que le dveloppeur crit, s'il dcide
de grer les transactions par programmation,
demeurera d'un trs haut niveau,
Simple vote pour un commit ou un abort,
Le container fait tout le travail en coulisse
3 manires de grer les transactions
1. Par programmation,
2. De manire dclarative,
3. De manire initie par le client.

Gestion des transactions par
programmation
Responsable : le
dveloppeur de
bean
Il dcide dans
son code du
begin, du
commit et du
abort
Ex: le banquier
Gestion des transactions dclarative
Le bean est automatiquement enrl (enrolled)
dans une transaction
Le container fait le travail
Gestion des transactions dclarative
Gnial pour le dveloppeur!
Transactions inities par le client

Que choisir ?
Par programmation : contrle trs fin
possible
Dclaratif : super, mais granularit importante,
Contrl par le client
N'empche pas de grer les transactions dans le
bean (par programmation ou de manire
dclarative)
Ajoute une couche de scurisation en plus, qui
permet de dtecter les crashes machine, rseau,
etc
Transactions et entits
Une entit n'accde pas la BD chaque
appel de mthode, mais chaque transaction.
Si une entit s'excute trop lentement, la cause
est peut-tre quune transaction est dmarre
pour chaque appel de mthode de lentit,
impliquant des accs BD.
Solution : inclure plusieurs appels de mthodes
de l'entit dans une mme transaction.
Se fait en prcisant les attributs de transaction
du bean.
Transactions et Message-Driven Beans
Bean-Managed Transactions
La transaction commence et se termine aprs que le message
a t reu par le MDB.
On indique dans le descripteur de dploiement les
aknowledgement modes pour indiquer au container comment
accuser rception
Container-Managed Transactions
La rception du message s'inscrit dans la mme transaction
que les appels de mthodes mtier du MDB. En cas de
problme, la transaction fait un rollback. Le container envoi
accus de rception (message acknowledgement)
Pas de transaction
Le container accusera rception aprs rception. Quand
exactement, ce n'est pas prcis
Transactions et Message-Driven Beans
Que choisir ?
Si on dcide de ne pas laisser le container grer les
transactions, on a pas de moyen de conserver le
message dans la queue de destination si un problme
arrive.
On choisit Container-Managed Transaction
Pige : si un MDB est expditeur et consommateur du
message, le tout intervient dans une mme transaction
Impossible de terminer ! Le message expdi n'est pas mis
dans la queue de destination de manire dfinitive tant que
l'envoi n'est pas commit.
Donc le message ne peut tre consomm! Cqfd.
Solution : appeler commit() sur l'objet JMS session juste
aprs l'envoi.
Attributs de transactions gres par le
container
Pour chaque bean, on prcise des attributs de
transaction
On peut spcifier des attributs pour le bean entier
ou mthode par mthode,
On peut prciser les deux Le plus restrictif gagne.
Chaque mthode mtier doit tre traite
(globalement ou individuellement)
Par dfaut : attribut = REQUIRED
Gnial pour le dveloppeur!
Valeur des attributs de transaction
Required
Le bean est toujours dans une transaction.
Si une transaction pour ce bean existe, alors le
bean la rejoint (join), sinon, le container cre une
nouvelle transaction.
La plupart du temps propos comme valeur
par dfaut par les IDEs
Attribut de transaction : Required
Exemple : passage d'une commande
Un session bean utilise deux entits : un bean carte de crdit
et bean commande,
Lors d'un passage de commande, on envoie la commande,
puis on dbite la carte de crdit,
Si le bean session a comme attribut de transaction Required,
une transaction est cre ds que le passage de commande
dmarre,
Lors de l'appel au bean Commande, si celui-ci est galement
en mode Required, il rejoindra la transaction en cours. Idem
lors de l'appel au bean Carte de Crdit,
Si un problme se pose, la carte de crdit ne sera pas dbite
et la commande ne sera pas passe.

Attribut de transaction : RequiresNew
RequiresNew
Le bean est toujours dans une nouvelle transaction.
Si une transaction existe, elle est suspendue,
Lorsque la nouvelle transaction se termine (abort ou
commit), l'ancienne transaction est rsume.
Utile si on veut respecter les proprits ACID
dans l'unit du bean, sans qu'une logique
externe intervienne.

Attribut de transaction : Supports
Supports
Semblable Required sauf que si une transaction
n'existe pas, elle n'est pas cre.
Si l'excution du bean intervient dans une
transaction existante, il la rejoint nanmoins.
A viter pour les applications mission-critical !
Dans ce cas, choisir Required.
Attribut de transaction : Mandatory
Mandatory
Une transaction doit exister lorsque le bean est
excut.
Si ce n'est pas le cas,
javax.ejb.TransactionRequiredException
est leve et renvoye au client.
Si le client est local, c'est
javax.ejb.TransactionRequiredLocalException qui
est leve
Attribut sr, qui oblige le client inscrire sa
logique dans une transaction avant d'appeler le
bean.
Attribut de transaction : NotSupported
NotSupported
Le Bean ne supporte pas les transactions,
Si une transaction existe lors de l'appel du bean, la
transaction est suspendue, le bean s'excute, puis
la transaction est rsume.
Utiliser cet attribut lorsque les proprits ACID
ne sont pas importantes
Exemple : un bean qui fait des statistiques toutes les
dix minutes en parcourant une BD. On tolre que les
donnes lues ne soient peut-tre pas jour
Gain en performance vident.
Attribut de transaction : Never
Never
Le Bean ne supporte pas les transactions,
Une exception javax.rmi.RemoteException ou
javax.ejb.EJBException est envoye au client
si une transaction existe au moment de l'appel du
bean.
A utiliser lors du dveloppement d'une logique
non transactionnelle.
Tous les attributs ne s'appliquent pas
tous les beans

Transactions gres par programmation
Plus complexes manipuler, mais plus
puissantes,
Le dveloppeur doit utiliser Java Transaction
API (JTA)
CORBA Object Transaction Service (OTS)
Dans une transaction de nombreux partis sont
impliqus : le driver de DB, le bean, le
container,
Premier effort pour assurer les transactions
dans un systme distribu : le service CORBA
Object Transaction Service (OTS)
OTS = ensemble d'interfaces pour le
gestionnaire de transactions, le gestionnaire de
ressources, etc
Mortel utiliser !
Java Transaction Service (JTS)
Sun Microsystems a encapsul OTS en deux
API distinctes
JTS s'adresse aux vendeurs d'outils capables
d'assurer un service de transaction, elle couvre tous
les aspects complexes d'OTS,
JTA s'adresse au dveloppeur d'application (vous)
et simplifie grandement la gestion de transactions
en contexte distribu.
Java Transaction API (JTA)
JTA permet au programmeur de contrler la
gestion de transaction dans une logique
mtier.
Il pourra faire les begin, commit, rollback, etc
Il peut utiliser JTA dans des EJB mais aussi
dans n'importe quelle application cliente.
JTA se compose de deux interfaces distinctes.
JTA : deux interfaces
Une pour les gestionnaires de ressources
X/Open XA (hors sujet pour nous)
Une pour le programmeur dsirant contrler
les transactions :

javax.transaction.UserTransaction

L'interface javax.transaction.UserTransaction
public interface
javax.transaction.UserTransaction {
public void begin();
public void commit();
public int getStatus();
public void rollback();
public void setRollbackOnly();
public void setTransactionTimeout(int);
}

Constantes de la classe
javax.transaction.Status
Constantes renvoyes par getStatus()
public interface javax.transaction.Status {
public static final int STATUS_ACTIVE;
public static final int STATUS_NO_TRANSACTION;
public static final int STATUS_MARKED_ROLLBACK;
public static final int STATUS_PREPARING;
public static final int STATUS_PREPARED;
public static final int STATUS_COMMITTING;
public static final int STATUS_COMMITTED;
public static final int STATUS_ROLLING_BACK;
public static final int STATUS_ROLLEDBACK;
public static final int STATUS_UNKNOWN;
}

Exemple de transaction gre par
programmation

Exemple de transaction gre par
programmation (suite)

Transactions inities par le client
C'est la dernire des mthodes prsentes au
dbut de ce chapitre
Il est ncessaire d'obtenir une rfrence sur un
objet UserTransaction, fourni par JTA
Via JNDI !
Faire attention ce que chaque transaction ne
dure pas longtemps !!!
Pige classique !
Transactions inities par le client (servlet
par ex)
try {
// Obtenir une transaction par JNDI
Context ctx = new InitialContext();
userTran = (javax.transaction.UserTransaction)
ctx.lookup("java:comp/UserTransaction");
userTran.begin();
// Operations de la transaction
userTran.commit();
} catch (Exception e) {
// Traiter les exceptions.
// Certaines peuvent provoquer un rollback.
}

Niveau d'isolation
Le niveau d'isolation limite la faon dont les
transactions multiples et entrelaces
interfrent les unes sur les autres dans une
BD multi-utilisateur.
3 types de violations possibles
1. Lecture impropre (ou brouille),
2. Lecture ne pouvant tre rpte,
3. Lecture fantme.
Niveau d'isolation
Lecture impropre
La transaction T1 modifie une ligne, la transaction T2 lit
ensuite cette ligne,
Puis T1 effectue une annulation (rollback),
T2 a donc vu une ligne qui n'a jamais vraiment exist.
Lecture ne pouvant tre rpte
T1 extrait une ligne,
T2 met jour cette ligne,
T1 extrait nouveau la mme ligne,
T1 a extrait deux fois la mme ligne et a vu deux valeurs
diffrentes.
Niveau d'isolation
Lecture fantme
T1 lit quelques lignes satisfaisant certaines
conditions de recherche,
T2 insre plusieurs lignes satisfaisant ces mmes
conditions de recherche,
Si T1 rpte la lecture elle verra des lignes qui
n'existaient pas auparavant. Ces lignes sont
appeles des lignes fantmes.
Niveau d'isolation

Attribut Syntaxe Description
Uncommited TRANSACTION_READ_UNCOMMITED Autorise l'ensemble des
trois violations
Commited TRANSACTION_READ_COMMITED

Autorise les lectures ne
pouvant tre rptes et
les lignes fantmes,
n'autorise pas les
lectures brouilles
Repeatable TRANSACTION_REPEATABLE_READ Autorise les lignes
fantmes mais pas les
deux autres violations
Serialisable TRANSACTION_SERIALIZABLE N'autorise aucune des
trois violations
Quel niveau utiliser
Uncommited
Uniquement si on est sr qu'une transaction ne pourra tre
mise en concurrence avec une autre.
Performant mais dangereux !
A viter pour les applications mission-critical !
Commited
Utile pour les applications qui produisent des rapports sur une
base de donne. On veut lire des donnes consistances,
mmes si pendant qu'on les lisait quelqu'un tait en train de
les modifier.
Lisent un snapshot des donnes commites
Niveau d'isolation par dfaut de la plupart des BD (Oracle)
et aussi le niveau disolation de JPA
Quel niveau utiliser
Repeatable
Lorsqu'on veut pouvoir lire et modifier des lignes,
les relire au cours d'une mme transaction, sans
perte de consistance.
Serialisable
Pour les applications mission-critical qui ncessitent
un niveau d'isolation absolu, ACID 100% !
Attention ,les performances se dgradent vitesse
grand V avec ce mode !

Comment spcifier ces niveaux ?
Transactions gres par le bean : appel de
Connection.SetTransactionIsolation(...).
aprs avoir rcupr la connexion, par exemple par
DataSource ds =
jndiCtxt.lookup("java:comp/env/jdbc/mabd");
ds.getConnection();
Transactions gres par le container
Non, on ne peut pas spcifier le niveau d'isolation dans
le descripteur !
On le fera via le driver JDBC, ou via les outils de
configuration de la DB ou du container,
Problmes de portabilit !

Impossibilit de spcifier le niveau
d'isolation ???

Deux stratgies
Lorsqu'on veut grer les transactions, on doit
toujours choisir entre deux stratgies
1. Stratgie pessimiste
On pense quil va y avoir des problmes, on prend
donc un verrou lors des accs BD, on fait notre
travail, puis on libre le verrou.
2. Stratgie optimiste
Espre que tout va bien se passer.
Nanmoins, si la BD dtecte une collision, on fait
un rollback de la transaction.
Que faire dans le code EJB ???
Ok, nous avons vu comment spcifier le type de
gestion de transaction, gre par le bean ou le
container,
Nous avons vu les niveaux d'isolations, que l'on
spcifie la plupart du temps via les pilotes JDBC,
Mais que faire en cas de rollback par exemple
On ne peut pas re-essayer indfiniment d'excuter une
transaction, on peut envoyer une Exception au client
On veut galement tre tenu au courant de ce qu'il se passe
pendant l'excution d'une transaction.
Que faire dans le code EJB ???
En cas de rollback, si on envoie une Exception
au client, que faire de l'tat du bean ?
Si le bean est stateful, on risque d'avoir un tat
incorrect (celui qui a provoqu l'chec de la
transaction),
Lors du design d'un bean, il faut prvoir la
possibilit de restaurer un tat correct,
Le container ne peut le faire pour vous car le
traitement est en gnral spcifique l'application,
Il peut nanmoins vous aider raliser cette tche.
Que faire dans le code EJB ???
L'EJB peut implementer une interface optionnelle
javax.ejb.SessionSynchronization
public interface javax.ejb.SessionSynchronization {
public void afterBegin();
public void beforeCompletion();
public void afterCompletion(boolean commited);
}
Uniquement pour les session beans stateful dont les
transactions sont gres par le container.

Que faire dans le code EJB ???
Le container appelle afterCompletion() que la
transaction se soit termine par un commit ou par un
abort
Le paramtre de la mthode nous signale dans quel
cas on se trouve
Que faire dans le code EJB ???
@Stateful
public class CountBean implements SessionSynchronization {
private int val;
private int oldVal;
public CountBean(int val) {
this.val=val;
this.oldVal=val;
}
public void afterBegin() { oldVal = val;}
public void beforeCompletion() {}
public void afterCompletion(boolean commited) {
if (! commited)
val = oldVal;
}
public int count() {
return ++val;
}
}

Vous aimerez peut-être aussi