139 votes

Lors de l'utilisation de SÉLECTIONNER ... POUR la mise à JOUR?

Merci de m'aider à comprendre les cas d'utilisation derrière SELECT ... FOR UPDATE.

Question 1: Est la suite d'un bon exemple de cas SELECT ... FOR UPDATE doit être utilisé?

Donnée:

  • les chambres[id]
  • les balises[id, nom]
  • room_tags[room_id, tag_id]
    • room_id et tag_id sont des clés étrangères

L'application veut la liste de toutes les salles et les balises, mais doit différencier entre des chambres avec pas de tags contre les chambres qui ont été enlevés. Si SELECT ... FOR UPDATE n'est pas utilisé, ce qui peut arriver, c'est:

  • Dans un premier temps:
    • chambres contient [id = 1]
    • tags contient [id = 1, nom = 'chats']
    • room_tags contient [room_id = 1, tag_id = 1]
  • Thread 1: SELECT id from chambres;
    • renvoie [id = 1]
  • Filetage 2: SUPPRESSION DE room_tags OÙ room_id = 1;
  • Filetage 2: SUPPRESSION DE chambres where id = 1;
  • Filetage 2: [valide la transaction]
  • Thread 1: SÉLECTIONNER des étiquettes.nom DE room_tags, balises OÙ room_tags.tag_id = 1 ET balises.id = room_tags.tag_id;
    • retourne une liste vide

Maintenant Thread 1 pense que la pièce n ° 1 n'a pas de balises, mais en réalité, la chambre a été supprimé. Pour résoudre ce problème, le Thread 1 devrait SELECT id FROM rooms FOR UPDATE, empêchant ainsi le Thread 2 à partir de la suppression de rooms jusqu'à ce que le Thread 1 est terminé. Est-ce exact?

Question 2: Quand doit-on utiliser SERIALIZABLE d'isolation de la transaction contre READ_COMMITTED avec SELECT ... FOR UPDATE?

Les réponses sont attendues pour être portable (pas de base de données spécifique). Si ce n'est pas possible, veuillez expliquer pourquoi.

106voto

Quassnoi Points 191041

Le seul portable de façon à assurer la cohérence entre les chambres et les balises et de faire assurer les chambres ne sont jamais retournés, après qu'ils avaient été supprimés est de les verrouiller avec SELECT FOR UPDATE.

Toutefois, dans certains systèmes de verrouillage est un des effets secondaires de contrôle de la simultanéité, et vous obtenir les mêmes résultats sans spécifier FOR UPDATE explicitement.


Pour résoudre ce problème, le Thread 1 devrait SELECT id FROM rooms FOR UPDATE, empêchant ainsi le Thread 2 à partir de la suppression de rooms jusqu'à ce que le Thread 1 est terminé. Est-ce exact?

Cela dépend du contrôle de la simultanéité de votre système de base de données.

  • MyISAM en MySQL (et de plusieurs autres anciens systèmes) verrouille l'ensemble de la table pour la durée d'une requête.

  • En SQL Server, SELECT des requêtes place des verrous partagés sur les dossiers / pages / tables qu'ils ont examiné, en tout en DML des requêtes place des verrous de mise à jour (qui, plus tard, à obtenir une promotion exclusive ou rétrogradé à des verrous partagés). Les verrous exclusifs sont incompatibles avec les verrous partagés, SELECT ou DELETE requête de verrouillage jusqu'à ce qu'une autre session s'engage.

  • Dans les bases de données qui utilisent MVCC (comme Oracle, PostgreSQL, MySQL avec InnoDB), un DML de la requête crée une copie de l'enregistrement (dans l'un ou l'autre manière) et généralement les lecteurs de ne pas bloquer les écrivains et vice versa. Pour ces bases de données, SELECT FOR UPDATE viendrait à portée de main: il serait bloquer soit SELECT ou DELETE de la requête jusqu'à ce qu'une autre session s'engage, comme SQL Server .

Quand doit-on utiliser REPEATABLE_READ d'isolation de la transaction contre READ_COMMITTED avec SELECT ... FOR UPDATE?

Généralement, REPEATABLE READ n'interdit pas d'fantôme lignes (les lignes qui apparaissaient ou disparaissaient dans une autre transaction, plutôt que d'être modifiée)

  • En Oracle et antérieures PostgreSQL versions, REPEATABLE READ est en fait un synonyme SERIALIZABLE. Fondamentalement, cela signifie que la transaction ne pas voir les changements effectués après qu'elle a commencé. Ainsi, dans cette configuration, le dernier Thread 1 de la requête sera le retour de la pièce comme si il n'a jamais été supprimé (ce qui peut ou peut ne pas être ce que vous voulez). Si vous ne voulez pas montrer les chambres après qu'ils ont été supprimés, vous devez le verrouiller les lignes avec des SELECT FOR UPDATE

  • En InnoDB, REPEATABLE READ et SERIALIZABLE sont des choses différentes: les lecteurs en SERIALIZABLE mode de jeu next-clés verrous sur les registres d'évaluer, de prévenir efficacement la simultanées DML . Si vous n'avez pas besoin d'un SELECT FOR UPDATE dans serializable mode, mais ne doivent en REPEATABLE READ ou READ COMMITED.

Notez que la norme sur les modes d'isolation ne prescrire que vous ne voyez pas certaines bizarreries dans vos requêtes, mais ne définit pas comment (avec dispositif de verrouillage ou avec MVCC ou autre).

Quand je dis "vous n'avez pas besoin d' SELECT FOR UPDATE" faut vraiment que j'ai ajouté "à cause des effets secondaires de certains moteur de base de données de mise en œuvre".

38voto

Colin 't Hart Points 3200

Des réponses courtes:

Q1: Oui.

Q2: N'a pas d'importance qui vous utilisez.

Réponse longue:

Un select ... for update volonté (comme il l'indique) sélectionner certaines lignes, mais aussi de les verrouiller, comme si ils ont déjà été mis à jour par la transaction en cours (ou comme si l'identité de mise à jour a été effectuée). Cela vous permet de mettre à jour à nouveau dans la transaction en cours, puis s'engager, sans autre transaction être en mesure de modifier ces lignes en quelque sorte.

Une autre façon de voir les choses, c'est comme si les deux instructions suivantes sont exécutées de manière atomique:

select * from my_table where my_condition;

update my_table set my_column = my_column where my_condition;

Depuis les lignes concernées par my_condition sont verrouillés, aucune autre transaction ne peut modifier d'une quelconque façon, et par conséquent, le niveau d'isolation de transaction ne fait pas de différence ici.

Notez également que le niveau d'isolation de transaction est indépendante de verrouillage: la définition d'un autre niveau d'isolation ne permet pas de contourner le verrouillage et la mise à jour des lignes dans une autre transaction qui sont bloqués par votre transaction.

Quels niveaux d'isolation de transaction ne de garantie (à différents niveaux) est la cohérence des données une fois les transactions sont effectuées.

1voto

Jorge Aguilar Points 1517

Bien cela peut dépendre de la DB que vous utilisez, mais aussi loin que Oracle lorsque vous utilisez le select for update, c'est comme vous le dites, lorsque vous sélectionnez les lignes à ajouter un verrou pour les lignes que vous vous regardez à ce moment, mais ils peuvent aussi être effacés ou mis à jour si nécessaire.

veuillez consulter ce lien de cause, les experts peuvent l'explique mieux que moi :D

http://www.techonthenet.com/oracle/cursors/for_update.php

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X