Documentation PostgreSQL 8.1.23 > Langage SQL > Contrôle d'accès simultané > Vérification de cohérence des données au niveau de l'application | |
Verrouillage explicite | Verrouillage et index |
Comme les lecteurs ne verrouillent pas les données avec PostgreSQL™, quelque soit le niveau d'isolation, les données lues par une transaction peuvent être surchargées par une autre transaction concurrente. En d'autres termes, si une ligne est renvoyée par SELECT, cela ne signifie pas que la ligne est toujours courante au moment où elle est renvoyée (c'est-à-dire, quelque temps après que la requête courante n'ait commencé). La ligne pourrait avoir été modifiée ou supprimée par une transaction validée après le lancement de cette requête. Même si la ligne est toujours valide « maintenant », elle pourrait être modifiée ou supprimée avant que la transaction courante ne soit validée ou annulée.
Une autre façon de penser à ceci est que chaque transaction voit une image du contenu de la base de données et les transactions concurrentes en cours d'exécution pourraient très bien voir des images différentes. Donc, le concept entier de « maintenant » est quelque peu mal défini. Ceci n'est habituellement pas un gros problème si les applications clientes sont isolées les unes des autres, mais si les clients peuvent communiquer via des canaux externes à la base de données, de sérieuses confusions pourraient survenir.
Pour s'assurer de la validité actuelle d'une ligne et pour la protéger contre les modifications concurrentes, vous devez utiliser SELECT FOR UPDATE, SELECT FOR SHARE ou une instruction LOCK TABLE appropriée (SELECT FOR UPDATE et SELECT FOR SHARE verrouillent uniquement les lignes renvoyées contre les mises à jours concurrentes alors que LOCK TABLE verrouille la table entière). Ceci doit être pris en compte lors du portage d'applications vers PostgreSQL™ depuis d'autres environnements (avant la version 6.5, PostgreSQL™ utilisait des verrous de lecture et, du coup, cette considération est aussi valable pour les versions antérieures à la version 6.5 de PostgreSQL™).
Des vérifications globales de validité requièrent une réflexion supplémentaire avec MVCC. Par exemple, une application bancaire pourrait souhaiter vérifier que la somme de tous les crédits d'une table est équivalente à la somme des débits d'une autre table lorsque les deux tables sont activement mises à jour. Comparer les résultats de deux commandes SELECT sum(...) successives ne fonctionnera pas correctement avec le mode de lecture validée car la deuxième requête a des chances d'inclure les résultats de transactions non comptabilisées dans la première. Faire les deux sommes dans une seule transaction sérialisée donnera une image plus précise des effets des transactions validées avant le début de la transaction sérialisable -- mais vous pourriez vous demander si la réponse est toujours juste au moment où elle est fournie. Si la transaction sérialisable a elle-même appliqué des modifications avant de tenter la vérification de cohérence, l'utilité de la vérification devient bien plus discutable car, maintenant, elle inclut des modifications apparues après le début de la transaction mais pas toutes. Dans de tels cas, une personne attentionnée pourrait souhaiter verrouiller toutes les tables nécessaires à la vérification pour obtenir une image indiscutable de la réalité. Un verrou de mode SHARE (ou plus important) garantit qu'il n'y a aucune modification non validée dans la table verrouillée, autres que celles de la transaction.
Il est à noter que si vous voulez vous reposer sur les verrous explicites pour éviter les changements concurrents, vous devriez utiliser le mode Read Commited, ou alors, dans le mode sérialisable, être attentif à l'obtention des verrous avant d'effectuer des requêtes. Un verrou obtenu par une transaction sérialisable garantit qu'aucune autre transaction modifiant la table n'est en cours d'exécution mais si l'image vue par la transaction est antérieure à l'obtention du verrou, elle pourrait être antérieure aux quelques modifications maintenant validées dans la table. Une image de la transaction sérialisable est généralement gelée au début de la première requête ou de la première commande de modification de données (SELECT, INSERT, UPDATE ou DELETE). Du coup, il est possible d'obtenir des verrous de façon explicite avant que l'image ne soit gelée.