cours/content/bdd_avancees/7-transactions/index.md

162 lines
6 KiB
Markdown

---
title: "Base de données avancées : Mise en œuvre des transactions"
date: 2022-03-29
tags: ["transaction"]
categories: ["Base de données avancées", "Cours"]
mathjax: true
---
Une transaction est une unité d'un programme qui accède à des données d'un SGBR
en lecture, écriture ou les deux. Une transaction accède à un **état cohérent**
de la base. Puis lors de son exécution l'état de la base **peut ne plus être
cohérent**. Lors de sa validation (on parle de *commit*), l'état de la base
**doit redevenir cohérent**.
Deux problèmes types peuvent se poser alors :
* problème systèmes: récupérabilité
* exécution concurente de plusieurs transactions: sériabilité.
Le système doit garantir les propriété ACID afin de preserver la cohérence des
données :
* Atomicité: soit **toutes** les opérations sont validées soit aucune.
* Cohérence: l'exécution d'une transaction jusqu'à sa validation doit laisser
la base dans un **état cohérent**.
* Isoliation: les transactions qui s'exécutent en concurence sont isolées les
unes des autres. Les modification effectuée par l'une ne doivent pas être
prise en comptes par une autre.
* Durabilité: si une transaction est validée, les modification qu'elle a
apportée à la base sont **persitantes**, même après le redémarrage du
service, une coupure de courant ou un crash
## L'exemple de la banque
Prenons un exemple de virement de 1000 euros d'un compte A vers un compte B:
1. Lire(A)
2. A = A - 1000
3. Ecrire(A)
4. Lire B
5. B - B + 1000
6. Ecrire(B)
Une fois la transaction terminée et validée, elle est réputée **durable**. Si
elle échoue à partir de l'etape 3, il faut s'assurer que les modifications ne
soient pas persistantes.
Les données sont alors **cohérente** : la somme de A est B est toujours la même/
Si une autre transaction accède à la base entre les étapes 3 et 6, elle trouvera
la base dans un état incohérent (A + B est inférieur et 1000 euros se
balladent...). **L'isolation** n'est pas assurée, la solution la plus simple
consisterai alors à **serialiser** les transaction.
## État d'une transaction
Une transaction peut avoir 5 états:
* Active: c'est une transaction en cours d'exécution
* Partiellement validée: entre la dernière action et la validation
* Échec: lorque l'exécution normale de la transaction ne peut avoir lieu
* Avortée: après que toutes les modifications faite par la transaction soient
annulées (rollback). Il est alors possible de réexécuter la transaction ou de
la supprimer.
* Validée: après l'exécution réussie de la dernière opération.
![États d'une transation](./images/etat_transaction.svg)
## Implémentation de l'atomicité
### Approche naïve
Nous pouvons commencer par une approche naïve : **copie intégrale de la base
lors d'une opération** avec gestion d'un **pointeur** qui mème vers la dernière
version cohérente de la base. Le pointeur est modifié seulement si la
transaction réussie.
En plus de ne permettre l'exécution d'une seule transaction (pas de gestion de
l'exécution concurrente), cette approche est lourde et coûteuse surtout si la
base est volumineuse.
### L'exécution concurrente
Dans ce cas de figure, plusieurs transaction peuvent s'exécuter en même temps.
Cette approche apporte une **meilleure utilisation des ressources** ( voir les
[cours de système]({{< ref "/systemes_exploitation/1-introduction/index.md" >}}),
ainsi on réduit le temps de réponses: une longue transaction ne bloque plus les
autres.
**Le contrôle de la concurence** est le mécanisme permettant l'interaction entre
les transaction tout en garantissant l'intégrité de la base.
#### Ordonnancement
Ici encore on peut se référer au cours de *système d'exploitation*, ici
l'ordonnancement défini la manière d'exécuter les transaction de manière
concurrente.
##### Ordonnancement en série
Soit \\(T_1\\) et \\(T_2\\) deux transactions ordonancées par \\(O_1\\), en
série \\(T_2\\) sera exécutée lorsque \\(T_1\\) sera terminée.
##### Ordonnancement entrelacé
Ici les actions réalisées par deux transaction s'exécutent de manières
entrelacées. Soit deux transactions \((T_2\)) et \((T_3\)), voici le plan
d'ordonnancement \\(O_2\\):
\\( \begin{array}{l|l}
T_1 & T_2 \\\
lire(A) & \\\
A := A + 1000 &\\\
ecrire(A) &\\\
& lire(A) \\\
& tmp := A * 0.2 \\\
& A := A - tmp \\\
& ecrire(A) \\\
lire(B) & \\\
B := B + 1000 & \\\
ecrire(B $ \\\
& lire(B) \\\
& B = B + tmp \\\
& ecrire(B) \\\
\end{array}
\\)
Dans l'exemple ci-dessus, l'entrelassement ne préserve pas les valeurs de A et
B. Les valeurs finales de notre version entrelacée ne correxpondent plus aux
valeurs de la version en série. **Nous sommes donc face à un problème**
#### Notion de sériabilité
Dans le cas d'opération de lecture / écriture, nous partons du principe que
chaque transaction prise à part conserve la coherence de la base. Ainsi
l'ordonnancement en série préserve la cohérence.
Un ordonnancement entrelace est dit *sérialisable* si son résultat est
**exactement le même** que s'il est exécuté en série.
L'ordonnancement \\(O_f\\) composé de n transaction \\(T_1, T_2, ... T_n\\) est
sérialisable si toutes les permutations possibles ne changent pas le résultat.
Il faut don tester \\(n!\\) possibilités de permutations.
Pour tester et trouver le bon ordonnancement, nous avons à notre disposition la
c-sériabilité.
##### c-seriabilité
Les instructions notées \\(t_x\\) et \\(t_y\\) des transactions \\(T_x\\) et
\\(T_y\\) ordonnancées par \\(O_n\\) accèdent au même objet \\(Q\\):
* ne sont **pas en conflit** si elles accèdent toutes des deux à \\(Q\\) en
lecture
* sont **en conflit** si l'une des deux (ou les deux) accède à \\(Q\\)en
écriture
Si notre ordonnancement \\(O_n\\) peut-être transformé en \\(O_n^'\\) par une
série de remplacement d'instructions non conflictuelle alors \\(O_n\\) et
\\(O_n^'\\) sont dit **c-équivalent**. \\(O_n\\) est c-sérialisable s'il est
c-équivalent à un ordonnancement en série.