web-dev-qa-db-fra.com

Puis-je sélectionner des données insérées dans la même transaction non validée?

C'est peut-être une question stupide pour les débutants, mais je ne trouve aucune réponse nulle part. Partout où j'ai lu sur le Transaction Isolation qui résout la visibilité des données dans les transactions simultanées. Ma préoccupation est le comportement au sein d'une même transaction.

Si je démarre une transaction, insère des données, vais-je pouvoir les sélectionner juste après - toujours dans la même transaction, mais non validée? Si oui, ce comportement peut-il être modifié d'une manière similaire à l'isolement de transaction mentionné dans le cas de transactions simultanées?

Pour être précis, je cible PostgreSQL 9.4.

23
NumberFour

Oui.
Tout ce que vous avez fait dans la même transaction est visible par les commandes ultérieures de la même transaction. Tout simplement pas à d'autres transactions jusqu'à ce qu'elles soient engagées. Cela est vrai pour tous niveaux d'isolement sauf Read uncommitted où des "lectures sales" sont possibles (mais cela n'affecte pas votre question en soi).

Il est implémenté avec le modèle MVCC (Multiversion Concurrency Control) basé sur TransactionId s déterminant l'âge relatif et la visibilité pour chaque ligne de table. Chaque nouvelle version de ligne écrite dans la même transaction obtient le même xmin et est considérée comme étant arrivée "en même temps".

Il existe un cas de coin pour plusieurs CTE (expression de table commune) dans la même commande. On pourrait penser que celles-ci sont exécutées séquentiellement, mais à moins qu'un CTE ne fasse référence à l'autre, leur séquence est arbitraire. Et tous voient le même instantané depuis le début de la requête. C'est pourquoi il est interdit de UPDATE la même ligne plus d'une fois dans plusieurs CTE de la même requête: serait ambigu.

Exemple:

Exemple avancé:

18
Erwin Brandstetter

Essayons :

CREATE OR REPLACE FUNCTION public.sp_get_user()
 RETURNS json
 LANGUAGE plpgsql
AS $function$BEGIN

INSERT INTO users (name, password) VALUES ('deadeye', 'test');
RETURN row_to_json(row) FROM (SELECT name, password FROM users WHERE name = 'deadeye') row;

END;$function$

Maintenant, testons:

SELECT sp_get_user();
{"name":"deadeye","password":"test"}

Ça marche ! Comme l'a dit Erwin, tout ce qui est fait dans une transaction est visible à l'intérieur de la transaction. L'isolement se fait uniquement entre différents threads.

4
DeadEye