Ce document a été créé à l'origine au début de 2004, lorsque SQLite version 2 était encore largement utilisé, et a été écrit pour présenter les nouveaux concepts de SQLite version 3 aux lecteurs qui étaient déjà familiers avec SQLite version 2. Mais de nos jours, la plupart des lecteurs de ce document n'ont probablement jamais vu SQLite version 2 et ne connaissent que SQLite version 3. Néanmoins, ce document continue à servir de référence faisant autorité sur la façon dont le verrouillage des fichiers de base de données fonctionne dans la version 3 de SQLite.

Le document ne décrit que le verrouillage pour l'ancien mécanisme de transaction en mode rollback. Le verrouillage pour le nouveau mode write-ahead log ou WAL est décrit séparément.

1.0 Verrouillage des fichiers et concurrence en SQLite version 3

SQLite Version 3.0.0 a introduit un nouveau mécanisme de verrouillage et de journalisation conçu pour améliorer la concurrence par rapport à la version 2 de SQLite et pour réduire le problème de famine des écrivains. Le nouveau mécanisme permet également des commits atomiques de transactions impliquant plusieurs fichiers de base de données. Ce document décrit le nouveau mécanisme de verrouillage. Le public visé est constitué de programmeurs qui veulent comprendre et/ou modifier le code du pager et de réviseurs travaillant à la vérification de la conception de SQLite version 3.

Présentation de la version 2.0

Le verrouillage et le contrôle de la concurrence sont gérés par la fonction module pager. Le module pager est chargé de rendre SQLite "ACID" (Atomic, Consistent, Isolated, and Durable). Le module pager s'assure que les changements se produisent tous en même temps, que soit tous les changements se produisent, soit aucun, que deux processus ou plus n'essaient pas d'accéder à la base de données de manière incompatible en même temps, et qu'une fois que les changements ont été écrits, ils persistent jusqu'à ce qu'ils soient explicitement supprimés. Le pager fournit également un cache mémoire d'une partie du contenu du fichier disque.

Le pager ne se préoccupe pas des détails des B-Trees, des encodages de texte, des indices, etc. Du point de vue du pager, la base de données consiste en un seul fichier de blocs de taille uniforme. Chaque bloc est appelé "page" et a généralement une taille de 1024 octets. Les pages sont numérotées en commençant par 1. Ainsi, les premiers 1024 octets de la base de données sont appelés "page 1" et les seconds 1024 octets sont appelés "page 2" et ainsi de suite. Tous les autres détails de codage sont gérés par des couches supérieures de la bibliothèque. Le pager communique avec le système d'exploitation en utilisant l'un de plusieurs modules (Exemples : os_unix.c, os_win.c) qui fournit une abstraction uniforme pour les services du système d'exploitation.

Le module pager contrôle efficacement l'accès pour des threads séparés, ou des processus séparés, ou les deux. Dans tout ce document, chaque fois que le mot "processus" est écrit, vous pouvez lui substituer le mot "thread" sans changer la véracité de la déclaration.

3.0 Verrouillage

Du point de vue d'un processus unique, un fichier de base de données peut se trouver dans l'un des cinq états de verrouillage suivants :

NON VERROUILLÉ Aucun verrou n'est détenu sur la base de données. La base de données ne peut être ni lue ni écrite. Toute donnée mise en cache en interne est considérée comme suspecte et soumise à une vérification par rapport au fichier de la base de données avant d'être utilisée. D'autres processus peuvent lire ou écrire la base de données selon leurs propres états de verrouillage. Il s'agit de l'état par défaut.
SHARED La base de données peut être lue mais pas écrite. N'importe quel nombre de processus peut détenir des verrous SHARED en même temps, donc il peut y avoir de nombreux lecteurs simultanés. Mais aucun autre thread ou processus n'est autorisé à écrire dans le fichier de la base de données tant qu'un ou plusieurs verrous SHARED sont actifs.
RESERVÉ Un verrou RESERVED signifie que le processus prévoit d'écrire dans le fichier de base de données à un moment donné dans le futur, mais qu'il ne fait actuellement que lire le fichier. Un seul verrou RESERVED peut être actif à la fois, bien que plusieurs verrous SHARED puissent coexister avec un seul verrou RESERVED. RESERVED diffère de PENDING en ce que de nouveaux verrous SHARED peuvent être acquis tant qu'il y a un verrou RESERVED.
PENDING Un verrou PENDING signifie que le processus qui détient le verrou veut écrire dans la base de données dès que possible et attend simplement que tous les verrous SHARED actuels soient levés pour pouvoir obtenir un verrou EXCLUSIVE. Aucun nouveau verrou SHARED n'est autorisé contre la base de données si un verrou PENDING est actif, bien que les verrous SHARED existants soient autorisés à continuer.
EXCLUSIF Un verrou EXCLUSIF est nécessaire pour pouvoir écrire dans le fichier de la base de données. Un seul verrou EXCLUSIF est autorisé sur le fichier et aucun autre verrou de quelque nature que ce soit n'est autorisé à coexister avec un verrou EXCLUSIF. Afin de maximiser la concurrence, SQLite s'efforce de minimiser le temps pendant lequel les verrous EXCLUSIFS sont maintenus.

La couche d'interface du système d'exploitation comprend et suit les cinq états de verrouillage décrits ci-dessus. Le module d'appel d'urgence ne suit que quatre de ces cinq états de verrouillage. Un verrou PENDING n'est toujours qu'un tremplin temporaire sur le chemin d'un verrou EXCLUSIVE et donc le module pager ne suit pas les verrous PENDING.

4.0 Le journal de Rollback

Lorsqu'un processus veut modifier un fichier de base de données (et qu'il n'est pas en mode WAL), il enregistre d'abord le contenu original inchangé de la base de données dans un journal de retour en arrière. journal de retour en arrière. Le journal de retour en arrière est un fichier disque ordinaire qui se trouve toujours dans le même répertoire ou dossier que le fichier de base de données et qui porte le même nom que le fichier de base de données avec l'ajout d'un élément -journal suffixe. Le journal de rollback enregistre également la taille initiale de la base de données afin que, si le fichier de base de données grossit, il puisse être tronqué à sa taille initiale lors d'un rollback.

Si SQLite travaille avec plusieurs bases de données en même temps (en utilisant la commande ATTACH), alors chaque base de données a son propre journal de rollback. Mais il y a aussi un journal d'agrégat séparé appelé le journal de rollback. super-journal. Le super-journal ne contient pas de données de page utilisées pour le rollback des modifications. Au lieu de cela, le super-journal contient les noms des journaux de rollback de base de données individuels pour chacune des bases de données ATTACHées. Chacun des journaux d'annulation de base de données individuels contient également le nom du super-journal. S'il n'y a pas de bases de données ATTACHées (ou si aucune des bases de données ATTACHées ne participe à la transaction en cours), aucun super-journal n'est créé et le journal de rollback normal contient une chaîne vide à l'endroit normalement réservé à l'enregistrement du nom du super-journal.

Un journal de rollback est dit chaud s'il doit être rollbacké afin de restaurer l'intégrité de sa base de données. Un journal chaud est créé lorsqu'un processus est au milieu d'une mise à jour de la base de données et qu'un crash du programme ou du système d'exploitation ou une panne de courant empêche la mise à jour de se terminer. Les journaux à chaud constituent une exception. Les journaux à chaud existent pour se remettre d'un plantage ou d'une panne de courant. Si tout fonctionne correctement (c'est-à-dire s'il n'y a pas de plantage ou de panne de courant), vous n'aurez jamais de journal chaud.

Si aucun super-journal n'est impliqué, alors un journal est chaud s'il existe et possède un en-tête non nul et que son fichier de base de données correspondant ne possède pas de verrou RESERVED. Si un super-journal est nommé dans le journal de fichier, alors le journal de fichier est chaud si son super-journal existe et s'il n'y a pas de verrou RESERVÉ sur le fichier de base de données correspondant. Il est important de comprendre quand un journal est chaud, donc les règles précédentes seront répétées dans les puces :

  • Un journal est chaud si...
    • Il existe, et
    • Sa taille est supérieure à 512 octets, et
    • L'en-tête du journal est non nul et bien formé, et
    • Son super-journal existe ou le nom du super-journal est une chaîne vide, et
    • Il n'y a pas de verrou RESERVÉ sur le fichier de base de données correspondant.

4.1 Traitement des journaux chauds

Avant de lire un fichier de base de données, SQLite vérifie toujours si ce fichier de base de données a un journal chaud. Si le fichier a effectivement un journal chaud, alors le journal est annulé avant que le fichier ne soit lu. De cette façon, nous nous assurons que le fichier de base de données est dans un état cohérent avant qu'il ne soit lu.

Lorsqu'un processus veut lire un fichier de base de données, il suit la séquence d'étapes suivante :

  1. Ouvrir le fichier de base de données et obtenir un verrou SHARED. Si le verrou SHARED ne peut pas être obtenu, échouer immédiatement et retourner SQLITE_BUSY.
  2. Vérifiez si le fichier de base de données a un journal chaud. Si le fichier n'a pas de journal chaud, nous avons terminé. Retournez immédiatement. S'il y a un journal chaud, ce journal doit être annulé par les étapes suivantes de cet algorithme.
  3. Acquérir un verrou PENDING puis un verrou EXCLUSIF sur le fichier de base de données. (Remarque : ne pas acquérir un verrou RESERVÉ car cela ferait croire aux autres processus que le journal n'est plus chaud). Si nous ne parvenons pas à acquérir ces verrous, cela signifie qu'un autre processus est déjà en train d'essayer d'effectuer le rollback. Dans ce cas, lâchez tous les verrous, fermez la base de données et renvoyez SQLITE_BUSY.
  4. Lisez le fichier journal et effectuez un rollback des modifications.
  5. Attendez que les modifications annulées soient écrites sur le stockage persistant. Cela protège l'intégrité de la base de données au cas où une autre panne de courant ou un crash se produirait.
  6. Supprimez le fichier journal (ou tronquez le journal à zéro octet de longueur si PRAGMA journal_mode=TRUNCATE est défini, ou mettez à zéro l'en-tête du journal si PRAGMA journal_mode=PERSIST est défini).
  7. Supprimez le fichier super-journal s'il est possible de le faire en toute sécurité. Cette étape est facultative. Elle est ici uniquement pour empêcher les super-journaux périmés d'encombrer le lecteur de disque. Voir la discussion ci-dessous pour plus de détails.
  8. Laissez tomber les verrous EXCLUSIVE et PENDING mais conservez le verrou SHARED.

Une fois que l'algorithme ci-dessus s'est déroulé avec succès, il est possible de lire le fichier de la base de données en toute sécurité. Une fois que toute la lecture est terminée, le verrou SHARED est abandonné.

4.2 Suppression des super-journaux périmés

Un super-journal périmé est un super-journal qui n'est plus utilisé pour quoi que ce soit. Il n'y a aucune obligation de supprimer les super-journaux périmés. La seule raison de le faire est de libérer de l'espace disque.

Un super-journal est périmé si aucun journal de fichier individuel ne pointe vers lui. Pour savoir si un super-journal est périmé, nous lisons d'abord le super-journal pour obtenir les noms de tous ses journaux de fichiers. Ensuite, nous vérifions chacun de ces journaux de fichiers. Si l'un des journaux de fichiers nommés dans le super-journal existe et renvoie au super-journal, alors le super-journal n'est pas périmé. Si tous les journaux de fichiers sont soit manquants, soit font référence à d'autres super-journaux ou à aucun super-journal du tout, alors le super-journal que nous testons est périmé et peut être supprimé en toute sécurité.

5.0 Écriture dans un fichier de base de données

Pour écrire dans une base de données, un processus doit d'abord acquérir un verrou SHARED comme décrit ci-dessus (éventuellement en annulant les changements incomplets s'il y a un journal chaud). Après l'obtention d'un verrou SHARED, un verrou RESERVED doit être acquis. Le verrou RESERVED signale que le processus a l'intention d'écrire dans la base de données à un moment donné dans le futur. Un seul processus à la fois peut détenir un verrou RESERVED. Mais les autres processus peuvent continuer à lire la base de données pendant que le verrou RESERVED est détenu.

Si le processus qui veut écrire est incapable d'obtenir un verrou RESERVED, cela doit signifier qu'un autre processus possède déjà un verrou RESERVED. Dans ce cas, la tentative d'écriture échoue et renvoie SQLITE_BUSY.

Après avoir obtenu un verrou RESERVÉ, le processus qui veut écrire crée un journal de rollback. L'en-tête du journal est initialisé avec la taille originale du fichier de base de données. L'espace dans l'en-tête du journal est également réservé pour un nom de super-journal, bien que le nom du super-journal soit initialement vide.

Avant d'apporter des modifications à une page de la base de données, le processus écrit le contenu original de cette page dans le journal de retour en arrière. Les modifications apportées aux pages sont d'abord conservées en mémoire et ne sont pas écrites sur le disque. Le fichier original de la base de données reste inchangé, ce qui signifie que les autres processus peuvent continuer à lire la base de données.

Finalement, le processus d'écriture voudra mettre à jour le fichier de base de données, soit parce que son cache mémoire s'est rempli, soit parce qu'il est prêt à livrer ses modifications. Avant que cela ne se produise, le rédacteur doit s'assurer qu'aucun autre processus ne lit la base de données et que les données du journal de retour en arrière sont en sécurité sur la surface du disque afin qu'elles puissent être utilisées pour revenir en arrière sur des changements incomplets en cas de panne de courant. Les étapes sont les suivantes :

  1. Assurez-vous que toutes les données du journal de rollback ont été réellement écrites sur la surface du disque (et ne sont pas simplement conservées dans le cache du système d'exploitation ou des contrôleurs de disque), de sorte que si une panne de courant se produit, les données seront toujours là après le rétablissement du courant.
  2. Obtenez un verrou PENDING puis un verrou EXCLUSIF sur le fichier de la base de données. Si d'autres processus ont encore des verrous SHARED, le rédacteur pourrait devoir attendre que ces verrous SHARED se lèvent avant de pouvoir obtenir un verrou EXCLUSIVE.
  3. Écriture de toutes les modifications de pages actuellement détenues en mémoire vers le fichier disque de la base de données d'origine.

Si la raison de l'écriture dans le fichier de base de données est que le cache mémoire était plein, alors le rédacteur ne commettra pas tout de suite. Au lieu de cela, le rédacteur pourrait continuer à apporter des modifications à d'autres pages. Avant que les modifications suivantes ne soient écrites dans le fichier de base de données, le journal de retour en arrière doit à nouveau être vidé sur le disque. Notez également que le verrou EXCLUSIF que le rédacteur a obtenu afin d'écrire dans la base de données initialement doit être maintenu jusqu'à ce que toutes les modifications soient validées. Cela signifie qu'aucun autre processus ne peut accéder à la base de données à partir du moment où le cache mémoire se déverse pour la première fois sur le disque jusqu'à la validation de la transaction.

Lorsqu'un écrivain est prêt à commettre ses changements, il exécute les étapes suivantes :

  1. Obtenir un verrou EXCLUSIF sur le fichier de base de données et s'assurer que tous les changements de mémoire ont été écrits dans le fichier de base de données en utilisant l'algorithme des étapes 1-3 ci-dessus.
  2. Videz toutes les modifications du fichier de base de données sur le disque. Attendez que ces modifications soient effectivement écrites sur la surface du disque.
  3. Supprimez le fichier journal. (Ou si le PRAGMA journal_mode est TRUNCATE ou PERSIST, tronquez le fichier journal ou mettez à zéro l'en-tête du fichier journal, respectivement). C'est à ce moment-là que les modifications sont validées. Avant de supprimer le fichier journal, si une panne de courant ou un crash se produit, le prochain processus qui ouvrira la base de données verra qu'il y a un journal actif et annulera les changements. Après la suppression du journal, il n'y aura plus de journal à chaud et les modifications persisteront.
  4. Faites tomber les verrous EXCLUSIF et PENDING du fichier de la base de données.

Dès que le verrou PENDING est libéré du fichier de base de données, les autres processus peuvent recommencer à lire la base de données. Dans l'implémentation actuelle, le verrou RESERVED est également libéré, mais ce n'est pas essentiel pour un fonctionnement correct.

Si une transaction implique plusieurs bases de données, alors une séquence de commit plus complexe est utilisée, comme suit :

  1. Assurez-vous que tous les fichiers individuels de la base de données ont un verrou EXCLUSIF et un journal valide.
  2. Créez un super-journal. Le nom du super-journal est arbitraire. (L'implémentation actuelle ajoute des suffixes aléatoires au nom du fichier de base de données principal jusqu'à ce qu'elle trouve un nom qui n'existe pas précédemment). Remplissez le super-journal avec les noms de tous les journaux individuels et videz son contenu sur le disque.
  3. Écrire le nom du super-journal dans tous les journaux individuels (dans l'espace réservé à cet effet dans les en-têtes des journaux individuels) et vider le contenu des journaux individuels sur le disque et attendre que ces changements atteignent la surface du disque.
  4. Videz toutes les modifications des fichiers de la base de données sur le disque. Attendez que ces modifications soient effectivement écrites sur la surface du disque.
  5. Supprimez le fichier super-journal. C'est l'instant où les modifications sont validées. Avant de supprimer le fichier super-journal, si une panne de courant ou un crash se produit, les journaux de fichiers individuels seront considérés comme chauds et seront annulés par le prochain processus qui tente de les lire. Après la suppression du super-journal, les journaux de fichiers ne seront plus considérés comme chauds et les changements persisteront.
  6. Supprimez tous les fichiers de journal individuels.
  7. Faites tomber les verrous EXCLUSIF et PENDING de tous les fichiers de la base de données.

5.1 La famine des écrivains

Dans SQLite version 2, si de nombreux processus lisent la base de données, il se pourrait qu'il n'y ait jamais un moment où il n'y a pas de lecteurs actifs. Et s'il y a toujours au moins un verrou de lecture sur la base de données, aucun processus ne pourrait jamais apporter de modifications à la base de données car il serait impossible d'acquérir un verrou d'écriture. Cette situation est appelée starvation de l'écrivain.

SQLite version 3 cherche à éviter la famine des écrivains par l'utilisation du verrou PENDING. Le verrou PENDING permet aux lecteurs existants de continuer mais empêche les nouveaux lecteurs de se connecter à la base de données. Ainsi, lorsqu'un processus veut écrire dans une base de données occupée, il peut poser un verrou PENDING qui empêchera les nouveaux lecteurs de se connecter. En supposant que les lecteurs existants finissent par terminer, tous les verrous SHARED finiront par se lever et l'écrivain aura une chance d'effectuer ses modifications.

6.0 Comment corrompre vos fichiers de base de données

Le module pager est très robuste mais il peut être subverti. Cette section tente d'identifier et d'expliquer les risques. (Voir aussi la section Les choses qui peuvent mal tourner de l'article sur Atomic Commit.

Il est clair qu'une défaillance du matériel ou du système d'exploitation qui introduit des données incorrectes au milieu du fichier de base de données ou du journal posera des problèmes. De même, si un processus malveillant ouvre un fichier de base de données ou un journal et écrit des données mal formées au milieu de celui-ci, la base de données sera corrompue. Il n'y a pas grand-chose à faire pour ce genre de problèmes, donc on ne leur accorde pas plus d'attention.

SQLite utilise les verrous consultatifs POSIX pour implémenter le verrouillage sur Unix. Sous Windows, il utilise les appels système LockFile(), LockFileEx(), et UnlockFile(). SQLite suppose que ces appels système fonctionnent tous comme annoncé. Si ce n'est pas le cas, il peut en résulter une corruption de la base de données. Il faut noter que le verrouillage consultatif POSIX est connu pour être bogué ou même non implémenté sur de nombreuses implémentations NFS (y compris les versions récentes de Mac OS X) et qu'il existe des rapports de problèmes de verrouillage pour les systèmes de fichiers réseau sous Windows. Votre meilleure défense est de ne pas utiliser SQLite pour des fichiers sur un système de fichiers réseau.

SQLite utilise l'appel système fsync() pour vider les données sur le disque sous Unix et il utilise la fonction FlushFileBuffers() pour faire de même sous Windows. Une fois encore, SQLite suppose que ces services du système d'exploitation fonctionnent comme prévu. Mais il a été signalé que fsync() et FlushFileBuffers() ne fonctionnent pas toujours correctement, en particulier avec certains systèmes de fichiers réseau ou des disques IDE bon marché. Apparemment, certains fabricants de disques IDE ont des puces de contrôleur qui signalent que les données ont atteint la surface du disque alors qu'en fait, les données sont toujours dans la mémoire cache volatile de l'électronique du disque. Il existe également des rapports indiquant que Windows choisit parfois d'ignorer FlushFileBuffers() pour des raisons non spécifiées. L'auteur ne peut vérifier aucun de ces rapports. Mais s'ils sont vrais, cela signifie que la corruption de la base de données est une possibilité suite à une perte de puissance inattendue. Il s'agit de bogues du matériel et/ou du système d'exploitation contre lesquels SQLite n'est pas en mesure de se défendre.

Si un système Linux ext3 Le système de fichiers est monté sans l'option "barrier=1" dans le paramètre /etc/fstab et le cache d'écriture du lecteur de disque est activé, alors une corruption du système de fichiers peut se produire à la suite d'une perte de puissance ou d'un crash du système d'exploitation. Le fait qu'une corruption puisse se produire ou non dépend des détails du hardwar de contrôle du disque.e; la corruption est plus probable avec les disques bon marché de qualité grand public et moins problématique pour les périphériques de stockage de classe entreprise dotés de fonctionnalités avancées telles que les caches d'écriture non volatiles. Divers experts d'ext3 confirment ce comportement. On nous dit que la plupart des distributions Linux n'utilisent pas barrier=1 et ne désactivent pas le cache d'écriture, donc la plupart des distributions Linux sont vulnérables à ce problème. Notez que c'est un problème de système d'exploitation et de matériel et qu'il n'y a rien que SQLite puisse faire pour le contourner. Autres moteurs de base de données ont également rencontré ce même problème.

Si un crash ou une panne de courant se produit et entraîne un journal chaud, mais que ce journal est supprimé, le prochain processus qui ouvrira la base de données ne saura pas qu'il contient des modifications qui doivent être rollbackées. Le retour en arrière n'aura pas lieu et la base de données sera laissée dans un état incohérent. Les journaux de rollback pourraient être supprimés pour un certain nombre de raisons :

  • Un administrateur pourrait faire le ménage après un crash du système d'exploitation ou une panne de courant, voir le fichier journal, penser que c'est de la camelote, et le supprimer.
  • Quelqu'un (ou un processus) pourrait renommer le fichier de la base de données mais omettre de renommer également le journal qui lui est associé.
  • Si le fichier de base de données a des alias (liens matériels ou logiciels) et que le fichier est ouvert par un alias différent de celui utilisé pour créer le journal, alors le journal ne sera pas trouvé. Pour éviter ce problème, vous ne devez pas créer de liens vers les fichiers de base de données SQLite.
  • La corruption du système de fichiers à la suite d'une panne de courant pourrait entraîner le renommage ou la suppression du journal.

Le dernier (quatrième) point ci-dessus mérite un commentaire supplémentaire. Lorsque SQLite crée un fichier journal sous Unix, il ouvre le répertoire qui contient ce fichier et appelle fsync() sur le répertoire, dans le but de pousser les informations du répertoire sur le disque. Mais supposons qu'un autre processus ajoute ou supprime des fichiers sans rapport avec le répertoire qui contient la base de données et le journal au moment d'une panne de courant. Les actions supposées sans rapport de cet autre processus pourraient avoir pour conséquence que le fichier journal soit supprimé du répertoire et déplacé dans le répertoire "lost+found". Ce scénario est peu probable, mais il pourrait se produire. Les meilleures défenses sont d'utiliser un système de fichiers de journalisation ou de garder la base de données et le journal dans un répertoire à part.

Pour un commit impliquant plusieurs bases de données et un super-journal, si les diverses bases de données étaient sur différents volumes de disque et qu'une panne de courant se produit pendant le commit, alors quand la machine revient, les disques pourraient être remontés avec des noms différents. Ou certains disques peuvent ne pas être montés du tout. Dans ce cas, les journaux de fichiers individuels et le super-journal peuvent ne pas être en mesure de se retrouver. Le pire résultat de ce scénario est que le commit cesse d'être atomique. Certaines bases de données peuvent être annulées et d'autres non. Toutes les bases de données continueront à être autoconsistantes. Pour se défendre contre ce problème, gardez toutes les bases de données sur le même volume de disque et/ou remontez les disques en utilisant exactement les mêmes noms après une panne de courant.

7.0 Contrôle des transactions au niveau SQL

Les modifications apportées au verrouillage et au contrôle de la concurrence dans la version 3 de SQLite introduisent également quelques changements subtils dans la façon dont les transactions fonctionnent au niveau du langage SQL. Par défaut, la version 3 de SQLite fonctionne en autocommit mode. En mode autocommit, toutes les modifications apportées à la base de données sont validées dès que toutes les opérations associées à la connexion actuelle à la base de données sont terminées.

La commande SQL "BEGIN TRANSACTION" (le mot-clé TRANSACTION est facultatif) est utilisée pour sortir SQLite du mode autocommit. Notez que la commande BEGIN n'acquiert aucun verrou sur la base de données. Après une commande BEGIN, un verrou SHARED sera acquis lors de l'exécution de la première instruction SELECT. Un verrou RESERVÉ sera acquis lorsque la première instruction INSERT, UPDATE ou DELETE sera exécutée. Aucun verrou EXCLUSIF n'est acquis avant que la mémoire cache ne se remplisse et ne doive être déversée sur le disque ou avant que la transaction ne soit validée. De cette façon, le système retarde le blocage de l'accès en lecture au fichier fichier jusqu'au dernier moment possible.

La commande SQL "COMMIT" ne commet pas réellement les modifications sur le disque. Elle réactive simplement l'autocommit. Puis, à la fin de la commande, la logique normale d'autocommit prend le relais et provoque l'engagement réel sur le disque. La commande SQL "ROLLBACK" fonctionne également en réactivant l'autocommission, mais elle définit également un drapeau qui indique à la logique d'autocommission de revenir en arrière plutôt que de commettre.

Si la commande SQL COMMIT active l'autocommit et que la logique d'autocommit tente ensuite de commettre le changement mais échoue parce qu'un autre processus détient un verrou SHARED, alors l'autocommit est désactivé automatiquement. Cela permet à l'utilisateur de réessayer le COMMIT plus tard, après que le verrou SHARED ait eu l'occasion de se libérer.

Si plusieurs commandes sont exécutées en même temps contre la même connexion de base de données SQLite, l'autocommit est différé jusqu'à ce que la toute dernière commande se termine. Par exemple, si une instruction SELECT est en cours d'exécution, l'exécution de la commande se met en pause lorsque chaque ligne du résultat est renvoyée. Pendant cette pause, d'autres commandes INSERT, UPDATE ou DELETE peuvent être exécutées sur d'autres tables de la base de données. Mais aucun de ces changements ne sera validé avant la fin de l'instruction SELECT originale.