Vous êtes sur la page 1sur 5

Filière Licence professionnelle GSIE - Auxerre

Introduction aux bases de données (partie 8)

Marie-Noëlle Terrasse - Département IEM, Université de Bourgogne

La concurrence d’accés est traitée selon diverses méthodes dans les SGBD. Nous allons voir sur des
exemples simples les problèmes qui se posent ainsi que les solutions classiques qui sont proposées. Nous
en viendrons ensuite aux choix faits par les concepteurs de PostgreSQL.

1 La concurrence d’accés : présentation générale


Les problèmes liés à la concurrence d’accés peuvent être vus sur l’exemple d’un système de réservation par
internet (pour plus de détails voir le cours de P. Rigaux, URL ci-dessous) dont la procédure de réservation
corrrespond à un algorithme du type :

action notation
vérifier le nombre d’éléments libres lire(el)
vérifier le compte du client lire(cpt)
modifier le compte écrire(el)
modifier le nombre d’éléments libres écrire(cpt)

Exercice 1- Ordre des réservations


On considère deux clients C1 et C2 qui accèdent au système de réservation et pour lesquels l’ordre
d’exécution est donné en Figure 1, exemple 1.
i) En supposant qu’il y a initialement 10 places, que C1 en réserve 5 et que C2 en réserve 10, que se
passe-t-il ?
ii) En supposant qu’il y a initialement 100 places, que C1 en réserve 5 et que C2 en réserve 10, quel est
l’état du système de réservation en fin ?
iii) Proposez au moins trois ordres d’exécution corrects.
On appelle sérialisabilité le fait de calculer des ordres corrects d’exécution de requêtes (c’est à dire des
ordres –non purement séquentiels– mais qui produissent le même effet qu’une exécution séquentielle). La
sérialisabilité est assurée par tous les SGBD mais selon des mécanismes différents ayant des contraintes
plus ou moins fortes.
Il peut aussi arriver (problème matériel ou logiciel, changement d’avis de l’utilisateur, etc.) qu’une réser-
vation ne soit pas menée jusqu’au bout.

Exercice 2- Terminaison correcte des réservations


On suppose que le client C1 interrompe sa réservation aprés avoir effectué l’opération écrire(el).
i) Quel problème se pose ? Comment y remédier ?

Les SGBD ont proposé la mise en place de transactions : ce sont des séquences d’opérations simples
(contenant plusieurs lectures et écritures de données dans la base) mais qui sont considérées comme
une seule opération complexe. Cette opération complexe doit alors être globalement menée à
son terme ou ne pas laisser de trace dans la base (comme si elle n’avait pas été commencée). On parle
d’atomicité d’une transaction. Une transaction peut être validée (par une instruction commit) ou invalidée
(par une instruction rollback ) et dans ce cas la base doit être inchangée. C’est le programmeur qui a la
charge de définir les points de début et de validation/invalidation des transactions.

Exercice 3- Annulation et concurrence


On considère maintenant l’exécution donnée en Figure 1, exemple 2.

1
2

C1 C2
C1 C2 lire(el)
lire(el) lire(cpt)
lire(cpt) écrire(el)
lire(el) lire(el)
lire(cpt) lire(cpt)
écrire(el) écrire(el)
écrire(cpt) écrire(cpt)
écrire(cpt) commit
écrire(el) écrire(cpt)
rollback

Exemple 1 Exemple 2

Fig. 1 – Exemples d’ordres d’exécution

i) Que se passe-t-il et d’où vient le problème ?


On appelle lecture sale (dirty read) ce schéma où une transaction lit les données modifiées mais pas encore
validées d’une autre transaction. On appelle recouvrabilité le fait de garantir qu’une transaction validée
ne sera pas annulée. On parle de recouvrabilité stricte si deux transactions ne peuvent pas accéder en
écriture à la même donnée. Les propriétés de recouvrabilité et de sérialisabilité sont indépendantes l’une
de l’autre.

Les principaux problèmes recensés sont :


Perte d’opération Une écriture par C1 entre une lecture et une écriture par C2.
Lecture sale Lecture de données non validées.
Lecture non répétable Deux lectures successives donnent des résultats différents (à cause d’une écri-
ture intermédiaire).

Afin de traiter ces problèmes complexes, les concepteurs de SGBD ont proposé les propriétés connues
sous l’acronyme ACID pour caractériser les transactions sans problème :
Atomicité Une transaction est une unité de validation/annulation.
Cohérence La base de données doit être en état cohérent avant et aprés la transaction.
Isolation Chaque transaction est isolée pendant son exécution (les lectures et écritures qu’elle effectue
sont invisibles pour les autres transactions).
Durabilité La validation est définitive (une transaction validée ne peut plus être annulée).

2 La concurrence d’accés : les mécanismes en jeu


Plusieurs mécanismes ont été proposés pour résoudre les problèmes de concurrence d’accés. La majeure
partie de ces mécanismes tourne autour du verrouillage.

Le verrouillage Une des méthodes de contrôle des accés concurrents (pour garantir les propriétés
ACID) est l’utilisation de verrous pour protéger les données des accés concurrents dangereux. L’utilisation
de verrous peut conduire à un interblocage : deux transactions attendent chacune une donnée dont l’autre
dispose. Le risque d’interblocage est manifeste dans le mécanisme de verrouillage à deux phases : dans
la première phase une transaction accumule tous les verrous dont elle a besoin, elle les libère dans
une seconde phase. Pour limiter les risques d’interblocage on utilise en général des verrous partagés
(permettant plusieurs lectures simultanées) et des verrous exclusifs (pour l’écriture).
3

Les exécutions obtenues par verrouillage à deux phases avec relâchement des verrous lors du commit ou
du rollback vérifient la propriété ACID et elles sont de plus sérialisables1.

La norme SQL2 recense, en plus du verrouillage strict (qui est la valeur par défaut), quatre niveaux
de protection (qui sont donnés ici du plus faible au plus fort) :
– READ UNCOMMITED : on peut alors avoir des lectures sales.
– READ COMMITED : pas de lecture sale mais deux lectures successives peuvent donner des résultats
différents.
– REPEATABLE READ : un tuple lu en début de transaction sera toujours lisible pendant la transaction
(mais de nouveaux tuples peuvent apparaître).
– SERIALIZABLE : la même lecture donnera le même résultat tout au long de la transaction. C’est le
mode par défaut.

Le MVCC Le Multi-Version Concurrency Control est une alternative au verrouillage dans laquelle
chaque transaction voit une image des données telles qu’elles étaient quelque temps auparavant. Chaque
transaction travaille donc comme si elle disposait de sa propre version de la base de données.

L’estampillage Cette autre méthode de contrôle consiste à associer un numéro d’ordre (une estampille)
à chaque transaction. En cas de conflit c’est le numéro d’ordre qui détermine laquelle des transactions
pourra s’exécuter : l’autre transaction étant alors rejetée. Le risque de ce mécanisme est de voir une
transaction indéfiniment rejetée.

3 La concurrence d’accés et Postgres


PostgreSQL utilise a priori le MVCC comme mécanisme de contrôle. Ceci permet de garantir la transac-
tion contre les données non cohérentes (venant de mises à jour effectuées par d’autres transactions). Il
est aussi possible d’utiliser des verrous sur une base Postgres.

3.1 Les modes d’isolation de PostgreSQL


PostgreSQL offre les niveaux d’isolation de lecture validée et sérialisable (READ COMMITED et SE-
RIALIZABLE).
Par défaut Postgres travaille en mode READ COMMITED : une requête SELECT voit seulement les
données qui ont été validées par des transactions concurrentes avant son propre lancement. Attention,
un SELECT voit par contre les effets des précédentes mises à jour effectuées dans sa propre transaction
(même si elles ne sont pas validées). Tout se passe comme si une requête SELECT voyait une image de
la base de données prise à l’instant où le SELECT a été lancé.
De même, les commandes UPDATE et DELETE ne trouveront que les lignes qui ont été validées avant
leur propre début.
Ce mode READ COMMITED permet de traiter les requêtes simples comme par exemple des transactions
(ci-dessous portant sur une table accounts avec deux attributs balance et acctnum) :

BEGIN;
UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 12345;
UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 7534;
COMMIT;

En cas de requêtes complexes, il peut y avoir des problèmes : il faut alors utiliser le mode SERIALIZABLE.
Une requête SELECT en mode SERIALIZABL voit seulement les données validées avant le début de
la transaction ; il ne voit jamais les données non validées ni même les modifications validées par des
transactions concurrentes pendant l’exécution de la transaction. SELECT voit une image de la base de
1 La réciproque n’est pas vraie : il existe des exécutions sérialisables qui ne peuvent pas être obtenues par verrouillage.
4

données prise au début de la transaction (et non pas au début de la requête SELECT). Les commandes
SELECT successives à l’intérieur d’une seule transaction voient donc toujours les mêmes données. On
aura par exemple (voir le site Postgres pour plus de détails) :

BEGIN TREXTERNE;
BEGIN

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;


SET VARIABLE

SELECT COUNT(*) FROM test;

count
-------
5
(1 row)

--
-- ici a lieu un INSERT INTO test
--

SELECT COUNT(*) FROM test;


count
-------
5
(1 row)

COMMIT TREXTERNE;
COMMIT;

Il est plus difficile d’utiliser le mode SERIALIZABLE car il peut conduire à des erreurs. En effet, une
transaction sérialisable ne peut pas modifier des lignes qui ont été changées par d’autres transactions
après son propre début. On a alors le message : ERROR : could not serialize access due to concurrent
update. A réception d’un tel message il faut donc que la transaction en cours soit annulée puis relancée
(par le programme). A ce prix, le mode SERIALIZABLE garantit que chaque transaction accède à une
vue totalement cohérente de la base de données.

3.2 A FAIRE
Vous devez créer sur le serveur local, machine ITII une base de données permettant de simuler un
système de réservation de places pour des matchs. Cette base est limitée à trois tables :
– Une table STADE avec les attributs NomStade, PlacesDispo.
– Une table MATCH avec les attributs NomMatch, NomStade, PlacesOccupées.
– Une table CLIENT avec les attributs NomClient et Solde.

Exercice 4- Test des transactions


i) Ecrire une transaction qui permet de réserver n places pour un match donné.
ii) Ecrire une transaction qui permet d’enregistrer l’agrandissement d’un stade (en augmentant le nombre
de places disponibles).
iii) Question facultative On lance deux fois (en concurrence) la transaction d’augmentation du stade
d’Auxerre (pour ajouter respectivement 1000 et 2000 places). Donner un exemple d’ordre d’exécution
non sérialisable puis un exemple d’ordre d’exécution non recouvrable.
5

iv) Proposer un ordre d’exécution pour l’exécution concurrente d’une réservation de 1500 places et un
agrandissement de 1000 places (portant sur le même stade).
v) Proposer un ordre d’exécution pour l’exécution concurrente de deux réservations (100 et 200 places
respectivement) pour le même match et le même client.

Exercice 5- Retour à la base RMLL


Vous pouvez maintenant ajouter à votre interface des options qui modifient la base de données RMLL.
Il est vivement conseillé de faire d’abord des tests sur la base locale (serveur ITII) avant de modifier la
base sur le serveur ufrsciencestech.

4 Bibliographie
Vous pouvez voir les liens suivants :
– Sur les SGBD en général
Cours en ligne de D. Donsez : http://www-adele.imag.fr/~donsez/cours/
Cours en ligne de P. Rigaux : cortes.cnam.fr:8080/BD/DOC/cbd.pdf
– Sur les transactions en PostgreSQL
http://www.linuxfrench.net/article.php3?id_article=652
– Le site Postgres
en anglais http://www.postgresql.org/docs
ou en français http://traduc.postgresqlfr.org/pgsql-fr/ (mais la traduction est parfois hasar-
deuse)

5 TP noté
Le document que vous devez rendre à l’issue de cette séquence doit comprendre au minimum :
1. Une introduction (de quelques lignes) pour expliquer le contexte de votre travail : de quoi il s’agit,
quel est l’objectif.
2. Un compte-rendu de la conception de votre interface pour la base RMLL :
– quels profils vous avez choisis et quelles fonctionnalités vous offrez pour chaque profil.
– comment vous avez organisé la navigation dans votre interface (comment change-t-on de fonc-
tionnalité pour un même profil, comment change-t-on de profil pour un même utilisateur, quel
est la profondeur maximum et moyenne de vos menus, etc.).
3. Un compte-rendu de la programmation de votre interface : quelle partie vous avez choisi de pro-
grammer, comment vous avez structuré votre programme, les difficultés rencontrées et les solutions
choisies.
Si vous avez eu le temps de programmer des options modifiant la base de données, vous devez
indiquer quelles précautions vous avez prises pour la gestion de concurrence.
N’oubliez pas, sil vous plait, d’indiquer l’adresse (URL) de votre interface pour que je puisse la
tester.
4. Une conclusion qui met en valeur ce que vous avez fait, discute des points délicats ou pouvant être
améliorés, etc..
Si vous avez le temps vous pouvez compléter votre dossier par un compte-rendu de l’exercice 4 de la
Section 3.2.