Recette #9:
ACIDe : comprendre les Transactions

Février 2011


Précédent

Table des matières

Suivant


ACID n'a rien à voir avec la chimie (pH).
Dans le monde des SGBD, c'est un acronyme pour:

  • Atomicity

  • Consistency

  • Insulation

  • Durability

En quelques mots:

  • un SGBD est destiné a stocker des données complexes : des relations et des contraintes complexes doivent être soigneusement vérifiées et validées. L'intégrité des données DOIT être préservé

  • a chaque requête de type INSERT, UPDATE or DELETE cette intégrité est menacée.
    Si un seul changement échoue (pour diverses raisons), c'est toute la BDD qui risque d'être altérée.

  • Tout SGBD basé sur ACID permet d'éviter ces situations.

Le concept sous-jacent est celui de l'approche par TRANSACTION :

  • une TRANSACTION délimite un groupe de requêtes SQL.

  • une TRANSACTION est destinée à être réalisée en une seule fois (atomic unit), avec une approche tout ou rien.

    • Si toutes les requêtes au sein d'une TRANSACTION marchent, la TRANSACTION peut alors être validée.

    • mais si une seule des requêtes échoue, alors toute la TRANSACTION échouera : et la BDD va rester dans le même état où elle se trouvait avant la TRANSACTION

Bon, procédons à quelques essais afin d emieux comprendre la notion de TRANSACTION.



BEGIN ;


CREATE TABLE test (
  ;  ;num INTEGER,
  ;  ;string TEXT) ;


INSERT INTO test (num, string)
  ;  ;VALUES (1, 'aaaa') ;


INSERT INTO test (num, string)
  ;  ;VALUES (2, 'bbbb') ;


INSERT INTO test (num, string)
  ;  ;VALUES (3, 'cccc') ;

  ;BEGIN initialise la TRANSACTION :


SELECT *
FROM test ;

Regardons maintenant le résultats :
Tout semble ok.



Quelques points importants:

  • nous avons une TRANSACTION non terminée, en attente

  • verifions :

    • ouvrez une seconde instance de spatialite_gui , en connectant la même BDD

    • voyez-vous la table test  ; ?

    • NON : simplement parce que cette table n'existe pas encore réellement. Elle n'existe que dans le contexte (privé) de la connexion avec la première instance de spatialite_gui, et n'est donc pas visible avec la deuxième connexion.

  • re-vérifions :

    • quittez les deux instances de spatialite_gui.

    • lancez à nouveau spatialite_gui.

    • il n'y a aucune table test : elle semble avoir disparu.

    • tout ceci résulte du fait que la TRANSACTION correspondante n'a jamais été confirmée.

    • En fermant la connexion, SQLite a invalidé toute opération réalisée au sein de la TRANSACTION, laissant ainsi la BDD vierge de toute modification.


COMMIT ;


ROLLBACK ;

une fois que l'on a amorcé (BEGIN)une TRANSACTION, elle reste en suspend.
vous pouvez :



Performance

L'utilisation des TRANSACTIONs vous parait trop complexe ? vous vous dites "je vais simplement ignorer tout ça ..."
Bien, mais sachez que SQLite est un SGBD entièrement basé sur ACID, et il est basé sur l'utilisation des TRANSACTIONs. Et ce n'est pas tout.
SQLite n'est en fait pas capable de fonctionner hors d'un contexte de TRANSACTION.
Chaque fois que vous oubliez  ; BEGIN / COMMIT, alors SQLite entre implicitement dans le mode AUTOCOMMIT:
chaque requête est considérée comme une TRANSACTION.

i.e. quand vous déclarez par exemple un INSERT INTO ... , SQLite les transforme (de manière transparente) en:
BEGIN ;
INSERT INTO ... ;
COMMIT ;

note : ceci est absolument sûr et acceptable lorsque vous insérez un petit nombre de données à la main.
Mais quand un programme C / C++ / Java / Python tente d'insérer des centaines et des centaines de lignes, la transaction représente une sécurité non négligeable. Le fait de ne pas spécifier explicitement les transactions va également ralentir le processus, qui se composera alors de centaines de transactions.

La méthode la plus appropriée pour insérer de nombreuses données est la suivante :

  • débuter une TRANSACTION (BEGIN)

  • boucler les INSERT autant de fois que nécessaire.

  • confirmer la transaction TRANSACTION (COMMIT).

Cette astuce améliorera grandement les performances.


bizarreries des connecteurs

Développeurs, soyez prudents: 

le C / C++ utilise directement l'API SQLite : les transactions sont à expliciter

  • sqlite3_exec (db_handle, "BEGIN", NULL, NULL, &err_msg) ;

  • sqlite3_exec (db_handle, "COMMIT", NULL, NULL, & ;err_msg) ;


Avec le connecteur Java / JDBC il faut d'abord quitter le mode autocommit puis déclarer un COMMIT lorsque nécessaire.

  • conn.setAutoCommit(false) ;

  • conn.commit() ;


Python suit une approche différente : la TRANSACTION est active de façon transparente à chaque fois.
La performance est toujours optimale.
Il faut par contre ne pas oublier d'effectuer conn.commit() avant de se déconnecter de la BDD, sinon tous les changements ne seront pas enregistrés ( un ROLLBACK est automatiquement réalisé


Précédent

Table des matières

Suivant


Author: Alessandro Furieri a.furieri@lqt.it
Traduced from English By RIVIERE Romain

This work is licensed under the Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) license.


Permission is granted to copy, distribute and/or modify this document under the terms of the
GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.