Oracle : Transactions et concurrence d'accès Objectifs : Comprendre le fonctionnement des transactions dans Oracle Comprendre l'interblocage dans Oracle Comprendre le fonctionnement du mode SERIALIZABLE dans Oracle Démarrer la machine virtuelle, puis charger le TP «6 : Transactions et concurrence d accès» Transactions Ce TP permet d observer la concurrence d accès, vous devrez donc ouvrir simultanément plusieurs connexions, pour simuler la connexion de deux utilisateurs. Toutes les connexions doivent être faites avec le compte transaction@di. Pour ouvrir deux connexions, ouvrez donc deux terminaux, puis ouvrez une connexion dans chacun ; du point de vue d Oracle, cela correspond à deux connexions distinctes. 1. Dans la première fenêtre exécuter successivement : UPDATE chiffres SET text_val='douze' WHERE num_val=1; Dans la seconde fenêtre exécuter : D'un point de vu théorique, la séquence d'exécution correspondant aux commandes saisies est donc : r1(chiffres1)w1(chiffres1)r1(chiffres1)r2(chiffres1) Dans la première connexion (T1) on exécute les requêtes suivantes : 1 lignes sélectionnées. SQL> UPDATE chiffres SET text_val='douze' WHERE num_val=1; 1 ligne modifiée. SQL> 1 douze 1 lignes sélectionnées. Dans la seconde connexion: SQL> 1 lignes sélectionnées. La modifcation faite par T1 sur la ligne 1 n est pas visible a. Le verrouillage à deux phases (tel qu'étudié en cours) autorise-t-il cette exécution? L exécution de l opération r2(chiffre1) devrait être bloquée jusqu à ce que T1 soit terminée, car w1 a posé un verrou en écriture. b. Quelle est la différence avec le fonctionnement observé? Oracle autorise par défaut la lecture des données même si elles sont en cours de modifcation par d autres
transactions. c. Dans la première fenêtre exécuter l'instruction COMMIT, puis afficher le contenu de chiffres (SELECT *...) dans chacune des fenêtres. Que constatez vous? Pourquoi? Dans T1 : SQL> commit; Validation effectuée. SQL> 1 douze Dans T2 SQL> 1 douze La modifcation faite par T1 devient visible dans T2. 2. Exécuter un COMMIT dans chaque fenêtre, puis exécuter dans l'ordre : a. Connexion 1 : DELETE FROM chiffres WHERE num_val=0; b. Connexion 1 : DELETE FROM chiffres WHERE num_val=1; c. Connexion 1 & 2 : SELECT * FROM chiffres; d. Connexion 1 : ROLLBACK; e. Connexion 1 : SELECT * FROM chiffres; Observer les données de la table chiffres à chaque étape et commenter ce que vous trouvez. En particulier, rappeler le rôle de ROLLBACK. T1 :SQL> DELETE FROM chiffres WHERE num_val=0; 1 ligne supprimée. T1 :SQL> DELETE FROM chiffres WHERE num_val=1; 1 ligne supprimée. T1 :SQL> SELECT * FROM chiffres; 5 cinq 9 lignes sélectionnées. T2 :SQL> SELECT * FROM chiffres; 0 zero Grégory Fonlupt - Oracle : Transactions et concurrence d'accès - 2/6
5 cinq 10 lignes sélectionnées. Comme précédemment, les deux transactions ne se bloquent pas. Les lignes supprimées dans T1 sont toujours visibles dans T2 T1 :SQL> ROLLBACK; Annulation (rollback) effectuée. En faisant un rollback T1 est terminée, le SELECT qui suit correspond donc à une nouvelle transaction. T3 :SQL> SELECT * FROM chiffres; 0 zero 5 cinq 10 lignes sélectionnées. La modifcation opérée par T1 (suppression de 0 ) a été annulée, la table chiffres a bien été remise dans l état où elle se trouvait en début de transaction. La modifcation faite par T2 n est pas visible par T3 T2 :SQL> SELECT * FROM chiffres; 0 zero 5 cinq 9 lignes sélectionnées. La modifcation opérée par T2 est toujours visibles. 3. Exécuter un ROLLBACK dans chaque fenêtre, puis exécuter dans l'ordre : a. Connexion 1 :UPDATE chiffres SET text_val='modifié par T1' WHERE num_val=5; b. Connexion 2 :UPDATE chiffres SET text_val='modifié par T2' WHERE num_val=6; c. Connexion 1 & 2 : SELECT * FROM chiffres; d. Connexion 2 :UPDATE chiffres SET text_val='modifié par T2' WHERE num_val=5; Grégory Fonlupt - Oracle : Transactions et concurrence d'accès - 3/6
e. Connexion 1 :ROLLBACK; f. Connexion 1 & 2 : SELECT * FROM chiffres; g. Connexion 2 :ROLLBACK; Que se passe-t-il? Pourquoi? Les points a. à c. se déroulent comme ce qui a été observé avant. La mise à jours reste possible même si la table chiffres est modifée ou lue par une autre transaction. Au point d. la requête est bloquée. T2 tente de mettre à jours la ligne 5, mais cette ligne a déjà été modifée par T1 Oracle met donc T2 en attente. Au point e. on met fn à T1, immédiatement la transaction 2 reprend. La fn de T1 a supprimé le verrou sur la ligne 5 et la requête d. a pu s exécuter. On peut donc conclure qu Oracle bloque les transactions lorsqu elles tentent de modifer une même ligne. 4. Refaire les mêmes exécutions que pour la question précédente, mais au point e. exécuter la requête UPDATE chiffres SET text_val='modifié par T1' WHERE num_val=6; Que se passe-t-il? Est ce qu une transaction est annulée? Une erreur d interblocage se produit dans T2 : SQL> UPDATE chiffres SET text_val='modifié par T2' WHERE num_val=5; UPDATE chiffres SET text_val='modifié par T2' WHERE num_val=5 * ERREUR à la ligne 1 : ORA-00060: détection d'interblocage pendant l'attente d'une ressource En effet T1 a modifé la ligne 5, puis T2 a modifé la ligne 6. Ensuite T2 doit modifer la ligne 5 et est donc bloquée (jusqu à la fn de T1). T1 essaye à son tours de modifer la ligne 6, mais ne peut pas car cette ligne est déjà verrouillée par T2. T1 doit donc attendre T2 qui elle même attend T1. C est donc bien un interblocage. On remarque que la transaction 1 ne continue pas pour autant. C est donc que la transaction 2 n est pas terminée. On peut le vérifer en regardant le contenu de la table chiffres depuis T2 : SQL> SELECT * FROM chiffres; 6 modifié par T2... 10 lignes sélectionnées. La modifcation faite par T2 est bien encore présente (mais visible uniquement dans T2), et le verrou associé a cette modifcation est toujours la. On peut donc en conclure qu en cas d interblocage Oracle retourne bien une erreur mais laisse le choix au client de terminer ou non la transaction en l annulant, ou de réessayer la requête à l origine de l interblocage. Niveaux d'isolation Ouvrez deux connexions SqlPlus. Lors de la préparation du TP une table games a été créée, dont le contenu est le suivant : CODEG NOMG PRIX ---------- -------------------- ---------- 1 Warcraft 3 100 2 Fifa 2005 150 3 The Sims 200 Pour ce TP, plusieurs scripts ont été créés. Ils permettent de lire et d'écrire dans cette table : r : Lecture des 3 enregistrements. war3 : Écriture sur l'enregistrement 1. fifa : Écriture sur l'enregistrement 2. sims : Écriture sur l'enregistrement 3. Ces scripts SQL se trouvent dans /home/oracle/bureau/games. Dans ce TP lorsque vous devez exécuter des opérations, vous devez utiliser ces scripts. Par exemple, l'opération r1 ou (r2) consiste à exécuter la commande @/home/oracle/bureau/games/r dans la connexion 1, l'opération w2[sims] la commande @/home/oracle/bureau/games/sims. Grégory Fonlupt - Oracle : Transactions et concurrence d'accès - 4/6
Le script annule permet de rétablir la table games a son état initial, et sera utilisé régulièrement. 1. Pour chacune des exécutions suivantes, vérifer le fonctionnement et noter les différences par rapport aux règles étudiées en cours du verrouillage à deux phases. Après chaque exécution, penser à faire les rollback/commit et à utiliser systématiquement le script annule pour revenir à la situation initiale. a. r1 r2 w1[fifa] r2 w1[war] r2 R1 r2 R2 Les modifcations faites dans T1 ne sont pas visibles dans T2, sans pour autant bloquer T2. Le Rollback terminant la transaction T1 annule les modifcations apportées à la table Games b. r1 r2 w1[fifa] r2 C1 r2 w1[fifa] r2 C1 r2 R2 A chaque commit depuis la première fenêtre, les modifcations effectuées deviennent visibles dans T2. On notera qu on a ici une anomalie de lecture incohérente dans T2 car la données ffa est modifée entre le début et la fn de T2. c. r1 r2 w1[fifa] w2[war] r1 r2 C1 C2 r1 r2 R1 R2 Les écritures ne se bloquent pas mutuellement car si elles concernent la même table elles ne portent pas sur la même ligne. d. r1 r2 w1[fifa] w2[war] r1 r2 w1[sims] w2[sims] r1 r2 C1 C2 r1 r2 T2 est bloquée au moment de w2[sims] car T1 a déjà modifé cette ligne. T2 reste bloquée jusqu à la fn de T1 (au commit) e. r1 r2 w1[fifa] w2[war] r1 r2 w2[fifa] w1[war] r1 r2 R1 R2 r1 r2 w2[fifa] bloque T2 car la ligne a déjà été modifée par T1. w1[war] provoque un interblocage car War a été modifée par T1 f. r1 r2 w1[war] C1 r2 w2[war] r2 C2 Les modifcations sont visibles après le commit. 2. Reprenez l'exécution 1.a, mais en utilisant le script r2 à la place de r. Ce script utilise pour la sélection la requête SELECT * FROM games FOR UPDATE. Quelles sont les conséquences pour chacune des exécutions vues en 1? Quel est l intérêt de la clause FOR UPDATE, quand faut-il l utiliser? On constate que toutes les exécutions sont bloquées lors de la seconde lecture. Le SELECT FOR UPDATE demande à Oracle de lire des données mais en les verrouillant comme s il s agissait d une écriture. Lorsque dans un traitement (dans une transaction) on sait que l on doit lire des données, et les modifer plus tard dans la transaction, il peut être intéressant de verrouiller en écriture dès le début de la transaction. On limite ainsi le les blocages entre transactions. Par exemple si on prend l exécution suiante :w2(x) r1(x)r1(y)r1(z)w1(y)w1(z)w1(x) Par défaut le blocage survient au moment de w1(x), mais T1 possède déjà des verrous sur y et z et aucune autre transaction ne peut plus modifer x ou y jusqu à la fn de T1 (et donc de T2 puisque T1 est bloquée par T2). En utilisant le SELECT FOR UPDATE au moment de r1(x) T1 est bloqué dès la lecture, et n a donc pas encore de verrou sur y et z (ni sur x). D autres transactions ne seront pas bloquées par T1. 3. Exécuter la commande ALTER SESSION SET ISOLATION_LEVEL=SERIALIZABLE dans chacune des connexions. Cette commande place les connexions à un niveau d'isolation dit sérialisable. a. Reprenez des exécutions de la question 1, et observer le comportement d'oracle avec ce niveau d'isolation. Au niveau serializable, dès que la transaction a commencée, toutes les modifcations (insert, update ou delete) faites par les autres transactions ne sont pas visibles même si elles sont validées (COMMIT). Par exemple en b. après l opération C1 (commit de T1) la mise à jours faites par T1 sur ffa n est pas visible dans T2 car T2 a commencé avant cette mise à jours. b. Expliquer l'erreur constatée lors de l'exécution f. Sur l'exécution f, on obtient une erreur au moment de W2[war3], Impossible de sérialiser l'accès pour cette transaction. Les deux transactions se trouvent au niveau sérialisable et débutent dès la lecture de la table Games (donc y compris l'enregistrement war3). La mise à jour par T1 se fait et peut être validée. En revanche au moment ou T2 veut modifer il y a un problème car cette ressource War3 a été modifée par T1 depuis le début de T2, il ne peut donc plus sérialiser car il faut qu'il conserve la valeur qu'avait war3 au début de T2, or celle ci a été modifé depuis. Donc l'écriture de T2 serait fausse car T2 a lu war3 avant que T1 lise et modife war3, et a donc une valeur incohérente. Grégory Fonlupt - Oracle : Transactions et concurrence d'accès - 5/6
Au niveau SERIALIZABLE on ne peut pas modifer une ressource qui a été modifée par une autre transaction. A la question d. on obtient la même erreur, pourtant on ne modife pas la même ligne. En fait, en mode sériablisable Oracle dispose pour la transaction d une copie des blocs modifés par les autres transactions avec leur contenu en début de transaction. Donc dès qu une seule ligne est modifée dans un bloc, toutes les autres lignes du même bloc ne sont plus modifables. Grégory Fonlupt - Oracle : Transactions et concurrence d'accès - 6/6