(Remarque: Ceci est pour MS SQL Server)
Dites que vous avez une table ABC avec une colonne d'identité de clé principale et une colonne de code. Nous voulons chaque rangée ici d'avoir un code unique et généré séquentiellement (basé sur une formule de contrôle de contrôle typique). P>
Dites une autre table def avec une seule ligne, qui stocke le code disponible suivant (Imaginez un aliment simple). P>
Je sais que la logique comme ci-dessous présenterait une condition de course, dans laquelle deux utilisateurs pourraient se retrouver avec le même code: P>
begin tran declare @x int select @x= nextcode FROM def waitfor delay '00:00:15' update def set nextcode = nextcode + 1 select @x commit tran
7 Réponses :
Vous pouvez définir la colonne sur une valeur calculée qui est persistée. Cela s'occupera de la condition de course.
colonnes calculées < / p>
Utilisation de cette méthode signifie que vous n'avez pas besoin de stocker le code suivant dans une table. La colonne de code devient le point de référence. P> Donnez la colonne les propriétés suivantes sous la spécification de colonne calculée. P> formule = dbo.getNextCode () p> est persisté = oui p>
Dans le corps de la fonction Comment accéder à la dernière valeur (c'est-à-dire persisté)?
Cela dépend vraiment de la conception de la table, mais l'exemple mis à jour que je donne devrait couvrir la plupart des cas.
Désolé - aurait dû poser deux questions dans le premier commentaire! Comment le code suivant est-il persisté, ou où peut-être?
Découvrez l'URL que j'ai ajouté à ma réponse.
Cela résoudra-t-il le problème de la condition de course? Et si deux clients l'appellent en même temps? (ou lire dans la colonne calculée en même temps)
Recap: p>
Alors, vous deviner couru cette fois dans deux fenêtres (A et B): p>
Essayez de mettre la déclaration d'attente après la mise à jour, avant que la livraison, et voir ce qui se passe. P>
Il s'agit en fait d'un problème courant dans les bases de données SQL et c'est pourquoi la plupart (tous?) d'entre eux ont des caractéristiques intégrées pour s'occuper de cette question d'obtenir un identifiant unique. Voici quelques éléments à examiner si vous utilisez MySQL ou Postgres. Si vous utilisez une base de données différente, je parie que le fournit quelque chose de très similaire. p>
Un bon exemple de ceci est des séquences Postgres que vous pouvez consulter ici: P>
mySQL utilise quelque chose appelé incréments automatiques. P>
Ce n'est pas une vraie condition de race. C'est plus un problème courant avec les transactions simultanées. Une solution consiste à définir une serrure de lecture sur la table et à une série de sérialisation en place. P>
Définissez le niveau d'isolation de la transaction sur Serializable.
À des niveaux d'isolation inférieurs, d'autres transactions peuvent lire les données d'une rangée lue (mais pas encore modifiée) dans cette transaction. Donc, deux transactions peuvent en effet lire la même valeur. À très faible isolement (lire non engagés), d'autres transactions peuvent même lire des données après avoir été modifiées (mais avant de s'engager) ...
Révision des détails sur les niveaux d'isolation SQL Server ici p>
SO suite est que le niveau d'isolement est une pièce crtitique ici pour contrôler quel niveau d'accès à d'autres transactions d'accès entrer dans celui-ci. p>
note. De lien , sur sérialisable em>
Les déclarations ne peuvent pas lire les données modifiées mais non encore engagées par d'autres transactions em>.
En effet, les verrous sont placés lorsque la ligne est modifiée, non lorsque le Trans code> se produit, de sorte que ce que vous avez fait peut toujours permettre à une autre transaction de lire l'ancienne valeur jusqu'au point où vous le modifiez. Donc, je modifierais la logique pour la modifier dans la même instruction que vous le lisez, mettez ainsi le verrouillage à la fois. P> begin tran
declare @x int
update def set @x= nextcode, nextcode += 1
waitfor delay '00:00:15'
select @x
commit tran
Je pense que vous voulez dire mise à jour def Set @ x = NextCode, NextCode + = 1 i>
Au fur et à mesure que d'autres intervenants ont mentionné, vous pouvez définir le niveau d'isolation de la transaction pour vous assurer que tout ce que vous avez "lu" à l'aide d'une instruction SELECT ne peut pas changer dans une transaction.
Vous pouvez également supprimer une serrure spécifiquement sur la table def. En ajoutant la syntaxe avec blocklock code> après le nom de la table, par exemple P> SELECT nextcode FROM DEF WITH HOLDLOCK
réponse tardive. Vous voulez éviter une condition de course ... p>
"Condition de course de la file d'attente du processus SQL Server" < / p>
Vous devriez revoir ma réponse tardive: l'accepté n'est pas correct ...