Disons que vous avez le code suivant (veuillez ignorer que c'est affreux):
BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else
À mon avis, cela ne gère PAS correctement la concurrence. Ce n'est pas parce que vous avez une transaction que quelqu'un d'autre ne lira pas la même valeur que vous aviez avant d'arriver à votre déclaration de mise à jour.
Maintenant, en laissant le code tel quel (je me rends compte que cela est mieux géré comme une seule instruction ou encore mieux en utilisant une colonne d'auto-incrémentation / d'identité), quels sont les moyens sûrs de le faire gérer correctement la concurrence et d'empêcher les conditions de concurrence qui permettent à deux clients d'obtenir la même chose valeur id?
Je suis presque sûr que l'ajout d'un WITH (UPDLOCK, HOLDLOCK)
au SELECT fera l'affaire. Le niveau d'isolement des transactions SERIALIZABLE semble également fonctionner car il interdit à quiconque de lire ce que vous avez fait jusqu'à la fin du transfert ( MISE À JOUR : c'est faux. Voir la réponse de Martin). Est-ce vrai? Vont-ils tous les deux fonctionner aussi bien? Est-ce que l'un est préféré à l'autre?
Imaginez faire quelque chose de plus légitime qu'une mise à jour d'ID - un calcul basé sur une lecture que vous devez mettre à jour. Il pourrait y avoir de nombreuses tables impliquées, dont certaines vous écrirez et d'autres que vous ne ferez pas. Quelle est la meilleure pratique ici?
Après avoir écrit cette question, je pense que les conseils de verrouillage sont meilleurs car vous ne verrouillez que les tables dont vous avez besoin, mais j'apprécierais la contribution de n'importe qui.
PS Et non, je ne connais pas la meilleure réponse et je veux vraiment avoir une meilleure compréhension! :)
update
qui peuvent être basés sur des données obsolètes? Dans ce dernier cas, vous pouvez utiliser larowversion
colonne pour vérifier si la ligne à mettre à jour n'a pas été modifiée depuis sa lecture.