Cursus
Atomicité dans les bases de données : L'épine dorsale des transactions fiables
L'atomicité est un concept fondamental dans les systèmes de base de données. Cela signifie qu'une transaction doit soit réussir complètement, soit ne pas s'exécuter du tout. En cas d'échec à mi-parcours, tout est annulé comme si rien ne s'était passé.
Pourquoi est-ce si important ? Imaginez que vous transfériez de l'argent d'un compte bancaire à un autre. Vous appuyez sur "Envoyer", l'application se charge pendant une seconde, puis quelque chose ne va pas. L'argent disparaît de votre compte, mais n'arrive jamais sur l'autre. Maintenant, il a juste... disparu. Ce scénario est exactement ce que l'atomicité est censée empêcher.
Vous avez peut-être déjà entendu parler de l'ACID. Il s'agit d'un ensemble de quatre propriétés clés que les bases de données utilisent pour s'assurer que les choses ne se désagrègent pas. L'atomicité est le premier élément de cette liste, et ce pour une bonne raison : sans elle, les autres éléments (cohérence, isolation et durabilité) n'ont pas beaucoup d'importance.
Dans cet article, nous examinerons ce que signifie l'atomicité, comment elle fonctionne et pourquoi elle est si importante dans les systèmes quotidiens tels que les banques et le commerce électronique. Nous verrons également comment différentes bases de données le mettent en œuvre et comment vous pouvez concevoir des systèmes atomiques capables de bien gérer les choses lorsqu'elles tournent inévitablement mal.
Qu'est-ce que l'atomicité ?
L'atomicité signifie qu'une transaction dans une base de données est indivisible. Soit il se déroule jusqu'au bout, chaque étape se déroulant comme prévu, soit il ne se déroule pas du tout. Il n'y a pas d'entre-deux. Pas de mises à jour à moitié terminées, pas de données partielles sauvegardées, pas de limbes bizarres où certaines choses réussissent et d'autres non.
Atomicité dans les SGBD. Source : Arpit Bhayani
Si une partie de la transaction échoue, l'ensemble est annulé comme si rien ne s'était passé. C'est ce qui fait de l'atomicité une garantie aussi puissante. Sans cela, vous risqueriez constamment de laisser vos données dans un état corrompu ou incohérent, en particulier dans les systèmes où plusieurs choses doivent se produire en séquence.
Examinons quelques scénarios du monde réel où l'atomicité fait (ou défait) le système :
Exemple 1 : Virement bancaire
Supposons que vous transfériez 100 $ de votre compte courant à votre compte d'épargne.
L'opération comporte deux volets :
- Déduire 100 $ du compte courant
- Ajoutez 100 $ à votre épargne
Sans atomicité, il est possible que l'étape 1 se termine et que l'étape 2 échoue, peut-être en raison d'un problème de réseau ou d'une panne de serveur. Félicitations, votre argent vient de disparaître dans le vide. L'atomicité garantit que soit les deux étapes réussissent, soit aucune ne réussit. En cas de problème, les 100 dollars restent exactement à l'endroit où ils se trouvaient au départ.
Exemple 2 : Inventaire et traitement des commandes
Vous achetez en ligne le dernier disque vinyle en édition limitée. Le système doit :
- Réduire les stocks d'une unité
- Confirmez votre commande
Sans atomicité, il peut réduire l'inventaire, mais s'effondrer avant que la commande ne soit confirmée. Le magasin pense maintenant qu'il n'y a plus de stock, mais personne ne reçoit l'enregistrement.
Le nombre de fois où cela m'arrive lors d'un achat en ligne est étonnant. En général, je ferme l'onglet et je souhaite bonne chance à leurs ingénieurs, mais il est fort probable que je n'essaierai plus d'acheter sur ce site à l'avenir. Qui sait comment ils traiteront mes données personnelles s'ils ne sont pas en mesure de garantir la fiabilité de leur fonction principale d'achat ?
Exemple 3 : Système de réservation de vols
La réservation d'un vol ne se limite généralement pas à la sélection d'un siège. Le système doit :
- Attribuer le siège
- Mise à jour de la disponibilité des sièges
- Chargez votre carte
Si la deuxième étape échoue et que la troisième est franchie, vous avez payé pour une place qui n'existe pas. Ce n'est pas l'idéal.
Exemple 4 : Synchronisation de la base de données et de l'index de recherche
Imaginons que votre application mette à jour la description d'un produit dans la base de données principale. Parallèlement, il doit mettre à jour l'index de recherche afin que les utilisateurs puissent trouver le produit avec la nouvelle description.
Si la mise à jour de la base de données réussit mais que la mise à jour de l'index échoue, les utilisateurs verront des résultats périmés ou ne trouveront pas du tout le produit.
L'importance de l'atomicité
Pourquoi l'atomicité est-elle si importante ?
Il existe de nombreuses raisons pour lesquelles une transaction peut être interrompue. Il peut s'agir d'une panne de courant, d'une panne de serveur ou d'une interruption du réseau à mi-parcours. Si l'atomicité n'est pas respectée, cette transaction peut n'être que partiellement achevée. Votre base de données se retrouve alors dans une situation délicate : certaines modifications ont été prises en compte, d'autres non, et vous ne disposez d'aucun moyen simple pour réparer le désordre.
C'est là que les bugs de données deviennent vraiment sournois. Les utilisateurs ne remarqueront peut-être rien d'anormal au début, mais au fil du temps, les choses s'accumulent. Vos analyses sont bizarres, les commandes disparaissent, les comptes ne sont pas soldés ou les tickets d'assistance augmentent parce que les utilisateurs ne trouvent pas ce qu'ils viennent de sauvegarder.
L'atomicité permet d'éviter tout cela en veillant à ce que :
- Une transaction peut se dérouler complètement ou ne pas se dérouler du tout.
- Le système peut se rétablir proprement même en cas de défaillance à mi-parcours.
- Vos données restent cohérentes, même en cas de panne du système ou d'accès simultanés.
Elle est également étroitement liée aux autres propriétés de l'ACID. Sans atomicité, la cohérence n'est plus possible, car vous ne pouvez pas appliquer les règles si la moitié des données est manquante, et l'isolation est rompue, car d'autres utilisateurs peuvent voir des données partielles provenant d'une transaction incomplète.
C'est particulièrement important si vous avez affaire à.. :
- Transactions en plusieurs étapes, où une action dépend d'une autre.
- Mises à jour de plusieurs lignes ou tableaux, lorsque des données connexes doivent être synchronisées.
- Les systèmes distribués, où certaines parties de la transaction se déroulent sur différentes machines ou bases de données.
Comment fonctionne l'atomicité dans la pratique
Derrière la simplicité du "tout ou rien" se cache un système étonnamment complexe. Lorsqu'une base de données exécute une transaction, elle en suit, prépare et protège activement chaque étape.
Voici un aperçu de ce qui se passe :
Le cycle de vie des transactions
- Commencez la transaction : Le système marque le début d'une transaction, isolant les modifications à venir du reste de la base de données.
- Exécuter l'opération : Cela inclut toutes vos insertions, mises à jour, suppressions ou toute autre magie SQL que vous effectuez.
- Validation ou retour en arrière : Si chaque opération réussit, la transaction est validée et les modifications deviennent permanentes. En cas d'échec, l'ensemble de la transaction est annulée.
Enregistrement et tenue d'un journal
Pour garantir l'atomicité, les bases de données écrivent des journaux de ce qui va se passer avant que cela ne se produise réellement. Ces journaux sont stockés séparément et agissent comme un plan de sauvegarde.
Si le système tombe en panne au milieu d'une transaction, il peut se référer au journal et annuler les modifications incomplètes, réappliquer les modifications terminées en toute sécurité et restaurer la base de données dans un état propre et cohérent.
Cette approche, parfois appelée WAL (Write-Ahead Logging) ou journalisation, est un élément clé de la récupération en cas de panne.
Retour en arrière et récupération
Lorsqu'une transaction échoue, la base de données ne se contente pas d'abandonner, elle annule soigneusement les modifications. Les lignes modifiées sont rétablies dans leur état d'origine, tous les verrous détenus par la transaction sont libérés et les journaux sont utilisés pour annuler les mises à jour partielles.
Désormais, en cas de panne, les routines de récupération interviennent au moment du redémarrage. Ils rejouent les journaux, résolvent les transactions inachevées et veillent à ce que la base de données reprenne là où elle s'est arrêtée, sans demi-état bizarre.
Performance et atomicité
Sans surprise, tout cela a un coût. L'atomicité introduit :
- Verrouillage: Pour éviter que d'autres personnes ne modifient les mêmes données en cours de transaction
- Transparent: Des mécanismes de journalisation et de retour en arrière
- Blocages: Lorsque plusieurs transactions attendent l'une de l'autre pour libérer des ressources
C'est pourquoi vous devez concevoir les transactions importantes avec soin. Si vous en faites trop en une seule fois, vous risquez de ralentir l'ensemble de votre système ou de rencontrer des problèmes de concurrence.
L'atomicité dans les systèmes de base de données populaires
L'atomicité est un concept fondamental dans toutes les grandes bases de données, mais sa mise en œuvre peut varier légèrement en fonction du moteur de stockage sous-jacent et de la philosophie de conception. Voyons comment PostgreSQL et MySQL (InnoDB) s'assurent que les transactions fonctionnent correctement.
PostgreSQL
Avant que les données ne soient écrites de façon permanente, PostgreSQL crée un journal d'écriture (WAL), l'enregistrement de chaque modification prévue dont nous avons parlé précédemment. Ce journal est stocké en toute sécurité et sert de plan de reprise en cas de problème au cours de la transaction.
Lorsqu'une transaction est validée, PostgreSQL vérifie le WAL, confirme que toutes les modifications sont complètes et valides, puis finalise les mises à jour. Si un problème survient à mi-parcours, la base de données utilise ce journal pour reprendre le travail incomplet.
Ce qui est formidable, c'est que tout cela se fait automatiquement en coulisses. Du point de vue du développeur, c'est transparent : vous écrivez une transaction et PostgreSQL garantit l'atomicité sans que vous ayez à gérer la complexité.
Aucune modification n'est visible pour les autres utilisateurs tant que la transaction n'est pas entièrement validée. Cela permet de conserver une certaine cohérence et d'éviter toute bizarrerie "à moitié sauvegardée" dans les environnements multi-utilisateurs.
PostgreSQL WAL. Source : AlgoMaster
Si vous souhaitez mettre la main à la pâte et créer vos propres bases de données pour tester les transactions, jetez un coup d'œil à notre cours sur PostgreSQL.
MySQL (InnoDB)
Le moteur de stockage InnoDB de MySQL prend également en charge les transactions atomiques, et son approche est conçue pour être à la fois fiable et performante.
À l'instar de PostgreSQL, InnoDB utilise un journal des transactions pour garder une trace des modifications avant de les valider. En cas d'échec, le journal est utilisé pour revenir à l'état antérieur à la transaction. Cela permet de s'assurer qu'aucune mise à jour partielle ne se faufile.
Une chose qu'InnoDB fait particulièrement bien est de regrouper les écritures. Cela permet de réduire les E/S sur disque et d'améliorer les performances tout en protégeant l'atomicité. Il utilise également les journaux d'annulation pour annuler les modifications lors d'un retour en arrière et les journaux de rétablissement pour la récupération en cas de panne.
Comme dans PostgreSQL, vous pouvez compter sur la base de données pour gérer ces mécanismes à votre place. Vous n'avez pas besoin d'écrire un code de retour en arrière personnalisé.
Principaux enseignements pour les ingénieurs et les architectes de données
Il y a quelques points à garder à l'esprit lorsque vous travaillez avec des transactions atomiques dans vos propres projets. L'idée générale est de considérer l'atomicité comme un défaut et non comme un luxe. Si vous construisez des systèmes qui modifient des données à plusieurs endroits à la fois (ce qui est le cas de la plupart d'entre eux), la conception de l'atomicité vous permettra de gagner du temps, de la sérénité et, éventuellement, de recevoir une notification d'incident à 3 heures du matin.
Choisissez la bonne base de données pour le travail
Toutes les bases de données ne gèrent pas l'atomicité de la même manière et tous les moteurs de stockage ne sont pas égaux. Si l'atomicité est essentielle dans votre cas d'utilisation (par exemple, finance, logistique, gestion de l'état de l'utilisateur), assurez-vous que votre base de données prend en charge des transactions ACID complètes. C'est particulièrement important si vous utilisez MySQL, où le choix du moteur de stockage est primordial.
Concevoir pour l'échec
Partez du principe que les choses iront mal, parce qu'elles iront mal. Enveloppez les opérations en plusieurs étapes dans des transactions et traitez les erreurs de manière appropriée. Soyez explicite avec vos déclarations BEGIN
,COMMIT
, et ROLLBACK
, ou utilisez des frameworks qui les gèrent en toute sécurité sous le capot.
La plupart des ORM modernes et des couches d'accès aux données offrent une prise en charge intégrée des transactions. Par exemple :
-
Dans Node.js, des bibliothèques comme Prisma et TypeORM vous permettent d'envelopper la logique dans un appel qui gère le commit/rollback en coulisses.
transaction()
qui gère le commit/rollback dans les coulisses. -
En Python, SQLAlchemy propose des gestionnaires de contexte (avec
session.begin():
) qui assurent la sécurité des livraisons et des retours en arrière. -
En Java, des frameworks comme Spring vous permettent d'annoter les méthodes avec
@Transactional
de sorte que la base de données traite tout de manière atomique, même en cas d'appels de fonctions multiples.
Ces outils facilitent grandement la mise en place d'une construction sûre par défaut. Ils réduisent le risque d'oublier un retour en arrière ou de mal gérer la logique de validation, en particulier lorsque votre application devient plus complexe.
Concilier performance et fiabilité
L'atomicité s'accompagne d'une certaine surcharge, en particulier dans le cas de transactions importantes. Décomposez les opérations massives dans la mesure du possible, évitez de verrouiller des tableaux entiers et faites en sorte que les transactions soient courtes et ciblées. Les transactions de longue durée augmentent le risque de conflits, de blocages et d'utilisateurs mécontents.
Comprendre les dépendances et l'isolement
Comme nous l'avons vu précédemment, l'atomicité n'existe pas dans le vide, mais conjointement avec la cohérence et l'isolement. Veillez à ce que les modifications connexes soient effectuées en même temps et réfléchissez à la manière dont les transactions simultanées peuvent interagir. Utilisez des niveaux d'isolation adaptés à votre charge de travail sans compliquer les choses à l'excès.
Propriétés ACID dans les SGBD. Source : DataCamp
Test avec des scénarios de défaillance réalistes
Ne vous contentez pas de tester les chemins du bonheur. Simulez ce qui se passe lorsque votre application se bloque au milieu d'une transaction ou lorsqu'une requête n'aboutit pas. Vous pouvez utiliser des points de défaillance ou simuler des défaillances de la base de données pour voir comment votre système se comporte sous la pression.
Conclusion
Si vous construisez des systèmes où plusieurs choses doivent se produire ensemble, l'atomicité n'est pas facultative, elle est essentielle. Qu'il s'agisse de transférer de l'argent entre des comptes, de mettre à jour des stocks ou de synchroniser des systèmes, l'atomicité permet de s'assurer que vos données ne se retrouvent pas en panne ou à moitié terminées.
Si vous souhaitez aller plus loin, pourquoi ne pas suivre notre cours sur la conception de bases de données? Vous apprendrez à concevoir des bases de données en SQL pour traiter, stocker et organiser les données de manière plus efficace.
Et si vous êtes intéressé par des articles et des tutoriels plus pratiques sur la conception de bases de données, consultez notre série sur la normalisation des bases de données :
Ingénieur logiciel senior, rédacteur technique et conseiller avec une formation en physique. Nous nous engageons à aider les jeunes entreprises à atteindre leur potentiel et à rendre des concepts complexes accessibles à tous.
FAQ
L'atomicité est-elle assurée au niveau du matériel ou par la base de données ?
L'atomicité est une garantie logicielle mise en œuvre par le moteur de base de données. Cependant, les bases de données s'appuient sur certains comportements du matériel, tels que les écritures sur le disque qui sont effacées dans l'ordre, pour assurer la durabilité et la récupération en cas de panne.
L'atomicité peut-elle être appliquée en dehors des bases de données, par exemple dans la logique applicative ou les API ?
Oui ! Si l'atomicité est une propriété formelle des bases de données, vous pouvez appliquer le même principe dans votre code : traitez les processus à plusieurs étapes comme des unités indivisibles. Par exemple, vous pouvez utiliser des transactions dans un ORM, des machines d'état ou des flux de travail à sécurité renforcée pour garantir la cohérence entre les limites des services. C'est particulièrement important lorsqu'il s'agit de paiements, de planification ou d'API de tiers.
Quelle est la différence entre l'atomicité et l'idempotence ?
L'atomicité consiste à s'assurer qu'une transaction se réalise pleinement ou ne se réalise pas du tout. L'idempotence consiste à s'assurer que lamême opération peut être répétée en toute sécurité sans que le résultat ne change. Les deux sont importants, en particulier dans les API et les systèmes distribués. L'atomicité protège l'intégrité des opérations en plusieurs étapes, tandis que l'idempotence facilite les nouvelles tentatives et la tolérance aux pannes.
Apprenez l'ingénierie des données avec DataCamp
Cours
Understanding Data Engineering
Cours