Le comportement que vous décrivez est normal et attendu dans toute base de données relationnelle transactionnelle.
Si PostgreSQL vous a montré la valeur edited
pour le premier SELECT
ce serait une erreur de le faire - cela s'appelle une "lecture sale", et c'est une mauvaise nouvelle dans les bases de données.
PostgreSQL serait autorisé à attendre au SELECT
jusqu'à ce que vous vous soyez engagé ou annulé, mais ce n'est pas requis par la norme SQL, vous ne lui avez pas dit que vous vouliez attendre, et il n'a pas à attendre pour une raison technique, donc il renvoie les données que vous avez demandées pour tout de suite. Après tout, jusqu'à ce qu'il soit validé, cette update
il n'y a qu'une sorte de chose - cela peut toujours arriver ou ne pas arriver.
Si PostgreSQL attendait toujours ici, vous vous retrouveriez rapidement dans une situation où une seule connexion pourrait faire quoi que ce soit avec la base de données à la fois. Pas assez pour les performances, et totalement inutile la grande majorité du temps.
Si vous souhaitez attendre une UPDATE
simultanée (ou DELETE
), vous utiliseriez SELECT ... FOR SHARE
. (Mais sachez que cela ne fonctionnera pas pour INSERT
).
Détails :
SELECT
sans FOR UPDATE
ou FOR SHARE
La clause ne prend aucun verrou au niveau de la ligne. Ainsi, il voit quelle que soit la ligne validée actuelle et n'est pas affecté par les transactions en cours qui pourraient modifier cette ligne. Les concepts sont expliqués dans la section MVCC de la documentation
. L'idée générale est que PostgreSQL est une copie sur écriture, avec une gestion des versions qui lui permet de renvoyer la copie correcte en fonction de ce que la transaction ou l'instruction pouvait "voir" au moment où elle a démarré - ce que PostgreSQL appelle un "instantané".
Dans la valeur par défaut READ COMMITTED
les instantanés d'isolement sont pris au niveau de l'instruction, donc si vous SELECT
une ligne, COMMIT
une modification d'une autre transaction, et SELECT
encore une fois, vous verrez des valeurs différentes même au sein d'une même transaction. Vous pouvez utiliser SNAPSHOT
isolation si vous ne voulez pas voir les modifications validées après le début de la transaction, ou SERIALIZABLE
isolation pour ajouter une protection supplémentaire contre certains types d'interdépendances de transactions.
Voir le chapitre sur l'isolation des transactions dans la documentation .
Si vous voulez un SELECT
pour attendre que les transactions en cours valident ou annulent les modifications apportées aux lignes sélectionnées, vous devez utiliser SELECT ... FOR SHARE
. Cela bloquera le verrou pris par un UPDATE
ou DELETE
jusqu'à ce que la transaction qui a pris le verrou soit annulée ou validée.
INSERT
est différent, cependant - les tuples n'existent tout simplement pas pour les autres transactions jusqu'à la validation. La seule façon d'attendre un INSERT
simultané s est de prendre un EXCLUSIVE
verrou au niveau de la table, vous savez donc que personne d'autre ne modifie la table pendant que vous la lisez. Habituellement, la nécessité de le faire signifie que vous avez un problème de conception dans l'application - votre application ne devrait pas s'en soucier s'il y a des insert
non validés est toujours en vol.
Voir le chapitre sur le verrouillage explicite de la documentation .