PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Verrou et transaction dans postgres qui devrait bloquer une requête

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 .