2010-03-01 6 views
3

J'ai une table SQL Server que j'utilise en file d'attente et elle est traitée par un multi-thread (et sera bientôt multiserveur) application. Je voudrais un moyen pour un processus de réclamer la ligne suivante de la file d'attente, l'indiquant comme "en cours de traitement", sans la possibilité que plusieurs threads (ou plusieurs serveurs) revendiquent la même ligne en même temps.Récupère la ligne "suivante" de la base de données SQL Server et l'affiche dans une seule transaction

Existe-t-il un moyen de mettre à jour un indicateur dans une ligne et de récupérer cette ligne en même temps? Je veux quelque chose comme ça psuedocode, mais idéalement, sans bloquer toute la table:

Block the table to prevent others from reading 
Grab the next ID in the queue 
Update the row of that item with a "claimed" flag (or whatever) 
Release the lock and let other threads repeat the process 

Quelle est la meilleure façon d'utiliser T-SQL pour y parvenir? Je me souviens avoir vu une déclaration une fois qui SUPPRIMERait des lignes et, en même temps, déposerait les lignes SUPPRIMÉES dans une table temporaire afin que vous puissiez faire autre chose avec elles, mais je ne peux pas le trouver maintenant.

Répondre

2

Vous pouvez utiliser la clause SORTIE

UPDATE myTable SET flag = 1 
WHERE 
id = 1 
AND 
flag <> 1 
OUTPUT DELETED.id 
3

L'essentiel est d'utiliser une combinaison de conseils de table, comme illustré ci-dessous, dans une transaction.

DECLARE @NextId INTEGER 
BEGIN TRANSACTION 

SELECT TOP 1 @NextId = ID 
FROM QueueTable WITH (UPDLOCK, ROWLOCK, READPAST) 
WHERE BeingProcessed = 0 
ORDER BY ID ASC 

IF (@NextId IS NOT NULL) 
    BEGIN 
     UPDATE QueueTable 
     SET BeingProcessed = 1 
     WHERE ID = @NextID 
    END 

COMMIT TRANSACTION 

IF (@NextId IS NOT NULL)  
    SELECT * FROM QueueTable WHERE ID = @NextId 

UPDLOCK verrouille la ligne suivante disponible qu'il trouve ce qui est disponible, ce qui empêche les autres processus de saisissant.
ROWLOCK garantira que seule la rangée individuelle est verrouillée (je n'ai jamais trouvé que ce soit un problème de ne pas l'utiliser car je pense qu'il n'utilisera qu'une rowlock de toute façon, mais plus sûr de l'utiliser).
READPAST empêchera un processus d'être bloqué, en attendant qu'un autre se termine.

+0

+1, ce que je pensais, mais vous avez répondu plus vite! J'ajouterais que 'READPAST' permet à un autre processus de ne pas attendre jusqu'à ce que vous débloquiez cette ligne, il peut ignorer cette ligne verrouillée et poursuivre la recherche d'une ligne où' BeingProcessed = 0' –

+0

@KM - c'est l'une des choses que je garde blog sur, donc c'est très frais dans mon esprit au mo! J'y arriverai ... à un moment donné! – AdaTheDev

+0

La clause OUTPUT (de l'autre réponse) est ce que je considérais à l'origine, mais j'avais oublié le nom de. Cette méthode offre-t-elle un avantage par rapport à cette clause, ou la clause reproduit-elle simplement ce que vous avez construit ici? – SqlRyan