| 10.0 Utilisation
des Transactions
Parfois, vous ne voulez
pas qu'une instruction prenne effet sans qu'une autre lui succède.
Par exemple, quand le propriétaire du The Coffee Break met à
jour le montant de café vendu chaque semaine, il aimerait aussi
mettre à jour le montant total des ventes jusqu'à maintenant.
Donc, il ne veut pas mettre à jour l'un sans mettre à jour
l'autre, sinon les données ne seraient pas crédibles. La
manière pour être sûr que toutes les actions et interactions
voulues s'effectuent est d'utiliser une transaction. Une transaction est
un jeu de une ou plusieurs instructions qui sont exécutées
ensembles de façon unitaire, donc toutes les instructions sont
exécutées, ou aucune.
10.1
Désactiver le mode Auto-commit
Quand une connexion
est crée, elle est en mode auto-commit. Ce qui veut dire que chaque
instruction SQL est traitée comme une transaction et prendra automatiquement
effet après sa bonne exécution. (Pour être plus précis,
une instruction SQL prend automatiquement effet sur la base de données
lorsqu'elle est terminée, et non pas quand elle est exécutée.
Une instruction est terminée quand tous ses résultats et
toutes ses mises à jour ont été rapportées.
Dans la plupart des cas, une instruction est terminée, puis les
changements prennent effets sur la base de données, puis elle est
exécutée).
La manière
d'autoriser deux ou plusieurs instructions à être groupées
dans une transaction est de mettre hors service le mode auto-commit. C'est
ce que nous faisons à la ligne suivante, où conn est notre
connexion active :
conn.setAutoCommit(false);
10.2 Pour que la
transaction prenne effet sur la BD
Une fois que le mode
auto-commit est désactivé, aucune instruction SQL ne prendra
effet jusqu'à ce que la méthode commit soit employée.
Toutes les instructions exécutées après l'appel de
la méthode commit seront inclues dans la transaction et donc,
pourront prendre effet en tant qu'unité. Le code qui suit, où
conn est la connexion active, illustre la transaction :
conn.setAutoCommit(false);
PreparedStatement updateVentes = conn.preparedStatement(
"UPDATE CAFE SET VENTE = ? WHERE NOM_CAFE LIKE ?");
updateVentes.setInt(1,50);
updateVentes.setString(2, "Colombian");
updateVentes.executeUpdate();
PreparedStatement updateTotal = conn.preparedStatement(
"UPDATE CAFE SET TOTAL = TOTAL + ? WHERE" +
"NOM_CAFE LIKE ?");
updateTotal.setInt(1,50);
updateTotal.setString(2,"Colombian");
updateTotal.executeUpdate();
conn.commit();
conn.setAutoCommit(true);
Dans cet exemple, le mode auto-commit est désactivé pour
la connexion conn, ce qui veut dire que les deux prepared statements updateVentes
et updateTotal prendront effet dans la base de données quand la
méthode commit est appelée. Quand la méthode commit
est appelée (automatiquement quand auto-commit est activée
ou explicitement quand il est désactivé), tous les changements
résultants des instructions de la transaction seront permanent.
Dans ce cas, cela signifie que les colonnes VENTES et TOTAL pour le café
Colombian ont été modifiées à 50 (Si TOTAL
était 0) et retiendra cette valeur jusqu'à ce qu'elle soit
modifié par une instruction.
La dernière
ligne de l'exemple précédent active le mode auto-comit,
ce qui veut dire que chaques instructions prendront dès lors effet
automatiquement sur la base de données quand elle sera terminée.
Vous reviendrez donc à l'état par défaut, celui où
vous n'avez plus à appeler la méthode commit. Il est conseillé
de désactiver le mode auto-commit uniquement quand vous être
en mode transaction. De cette façon, vous réduisez les chances
de conflit au niveau des entrées dans la base de données
avec les autres utilisateurs.
10.3 Utiliser les
transactions pour préserver l'intégrité des données
En plus de grouper
les instructions ensembles pour être exécutées unitairement,
les transactions peuvent aider à préserver l'intégrité
de données dans une table. Par exemple, imaginons qu'un employé
était supposé entrer les nouveaux prix du café dans
la table CAFE, mais ne l'a pas fait depuis quelques jours. Pendant ce
temps, les prix ont augmentés, et le propriétaire décide
de mettre à jour les nouveaux prix dans la table. L'employé
se décide finalement à entrer les prix n'étant plus
à jour dans la base de données en même temps que le
propriétaire met à jour la table. Après avoir insérer
les prix non à jour, l'employé réalise qu'ils ne
sont plus valides, et donc appel la méthode rollback de l'objet
Connexion afin d'annuler les effets de ses manipulations. (La méthode
rollback met fin à une transaction et restaure les valeurs présentes
avant qu'elles aient été mises à jour) Mais en même
temps, le propriétaire exécute une instruction SELECT puis
affiche les nouveaux prix. Dans cette situation, il est possible que les
prix affichés par le propriétaire proviennent d'un rollback
contenant les anciens prix, rendant l'affichage des prix incorrects.
Ce genre de situation
peut être évitée en utilisant les transactions. Si
un SGBD supporte les transactions, et la plupart le font, il fournira
certains niveaux de protection contre les conflits qui peuvent survenir
quand on accède à des données au même moment.
Pour éviter
les conflits durant une transaction, un SGBD utilise des verrous, mécanisme
bloquant l'accès aux données utilisées par la transaction
aux autres utilisateurs. Une fois qu'un verrou est posé, il restera
en place jusqu'à ce qu'une transaction soit envoyée vers
la base de données pour qu'elle puisse y prendre effet, ou vers
un rollback. Par exemple, un SGBD pourra verrouiller la ligne d'une table
jusqu'à ce que les mises à jour aient été
validées. L'effet de ce verrou peut être de prévenir
un utilisateur contre les valeurs erronées.
La manière
dont les verrous sont posés détermine le niveau d'isolation
de la transaction, pouvant aller jusqu'à bloquer totalement les
transactions.
Un exemple de niveau
d'isolation de transaction est TRANSACTION_READ_COMMITTED qui n'autorise
l'accès à aucune valeur jusqu'à ce qu'elles aient
été validées dans la base de données. En d'autre
terme, si le niveau d'isolation de la transaction est TRANSACTION_READ_COMMITED,
le SGBD ne permettra donc pas de pouvoir lire des valeurs erronées.
L'interface Connexion inclue cinq niveaux d'isolation que vous pourrez
utiliser avec JDBC.
Normalement vous n'avez
pas besoin de faire quoi que ce soit en ce qui concerne le niveau d'isolation
de transaction, vous pouvez toujours utiliser celui par défaut
de votre SGBD. JDBC vous permet de savoir quel niveau d'isolation votre
SGBD utilise (par le biais de la méthode getTransactionIsolation)
et vous permet aussi de définir un autre niveau que celui utilisé
(grâce à setTransactionIsolation). Gardez à l'esprit
que même si JDBC vous permet de définir un niveau de transaction,
il faut quand même que les drivers utilisés et le SGBD utilisé
le supporte.
10.4 Quand appeler
la méthode RollBack
Comme mentionné
plus tôt, appeler la méthode rollback annule une transaction
et remet les valeurs qui ont été modifiées à
leurs valeurs originales. Si vous essayez d'exécuter une ou plusieurs
instructions dans une transaction et que vous avez une SQLExeption, vous
devrez utilisez la méthode rollback pour annuler la transaction
et la recommencer depuis le début. C'est la seule façon
d'être sûr de ce qui a été pris en compte sur la base
de données, et ce qui ne l'a pas été. Une SQLException
vous indique que quelque chose ne fonctionne pas, mais elle ne vous indique
pas ce qui à été pris en compte ou pas. Donc vous
ne pouvez pas compter sur le fait que rien n'a été mis à
jour sur la BD, appeler la méthode rollback est la seule façon
d'être sûr.
Précédent
Suivant
|