2011-07-20 5 views
1

Je fais une application financière dans laquelle je m'attends à un problème de simultanéité des données. Supposons qu'il existe un compte ABC qui contient 500 $. L'utilisateur du Web peut transférer ces fonds vers d'autres comptes. Cela impliquera 2 étapes 1er vérification de la disponibilité des fonds et 2ème transfert. Je fais une transaction et je fais les deux actes. Problème est quand à un moment (disons Time1) il y a 2 ou 3 demandes séparées pour transférer (disons transaction1, transaction2, transaction3) même quantité. Le montant disponible maintenant disponible est de 500 $. Si toutes les traductions commencent en même temps, tout le test sera le montant (500 $) disponible? ce qui sera vrai et la prochaine déclaration transférera des fonds à un autre compte.comment gérer ce problème de concurrence de données?

J'ai lu des informations sur les niveaux d'isolation des transactions, mais je ne pouvais pas décider quel niveau d'isolation je devais utiliser, en fait je suis confus dans sa compréhension. Aidez-moi, s'il vous plaît.

Merci

Répondre

1

Le but est d'empêcher un autre processus de lecture de l'équilibre, mais de minimiser le blocage pour les autres utilisateurs. Il faut donc utiliser la « table comme une file d'attente » de type mèches ainsi:

SET XACT_ABORT, NOCOUNT ON; 
BEGIN TRY 

    BEGIN TRANSACTION 

    SELECT @balance = Balance 
    FROM SomeTable WITH (ROWLOCK, HOLDLOCK, UPDLOCK) 
    WHERE Account = 'ABC' 

    --some checks 

    UPDATE ... 

    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    ... 
END CATCH 

L'alternative est de le faire dans un, ce qui est plus faisable s'il y a une table impliquée. Le CROSS JOIN est un test pour

SET XACT_ABORT, NOCOUNT ON; 
BEGIN TRY 

    --BEGIN TRANSACTION 

    UPDATE SomeTable WITH (ROWLOCK, HOLDLOCK, UPDLOCK) 
    SET Balance = Balance - @request 
    WHERE 
     ST.Account = 'ABC' AND Balance > @request; 
    IF @@ROWCOUNT <> 1 
     RAISERROR ('Not enough in account', 16, 1); 

    --COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    ... 
END CATCH 
+0

Merci GBN, il semble belle solution. Il y a deux questions à ce sujet. 1. Devrai-je également débloquer le verrouillage ou le valider automatiquement? 2. Est-ce pris en charge dans SQL Server 2005 sur les hébergements partagés? Merci – user576510

+1

1. Automatique à la validation (HOLDLOCK change la durée). 2. Oui: c'est la norme SQL – gbn

+0

en cas de rollback sont locak automatiquement libérés aussi bien? – user576510

0

Afin d'éviter des montants plus importants se retire que le prix, vous pouvez le faire:

update <table> 
set amount = amount - @price 
where amount >= @price 
and account = @account 

if @@rowcount = 1 print 'transaction went well' else print 'Insufficient funds' 
+0

Ce n'est pas assez concurrente sous très haute charge – gbn

+0

à cause de saignées? –

+0

Un deuxième processus pourrait lire le solde avant qu'il ne soit réellement changé. Le verrou exclusif est pour le changement, pas le bit WHERE. Donc c'est UPDLOCK qui fait ça. ROWLOCK empêche le verrouillage de plus d'une ligne pour la concurrence. – gbn

Questions connexes