2010-11-05 4 views
6

J'ai une table qui est lue en même temps par des threads différents.Ignorer la ligne verrouillée dans une requête MySQL

Chaque thread doit sélectionner 100 lignes, exécuter des tâches sur chaque ligne (sans rapport avec la base de données) puis supprimer la ligne sélectionnée de la table.

lignes sont sélectionnées en utilisant cette requête:

SELECT id FROM table_name FOR UPDATE; 

Ma question est: Comment puis-je ignorer (ou ignorer) les lignes qui ont été préalablement verrouillée à l'aide d'une instruction select dans MySQL?

Répondre

15

-je créer généralement une colonne id_processus qui est NULL par défaut et ensuite chaque thread utiliser un identifiant unique pour effectuer les opérations suivantes:

UPDATE table_name SET process_id = #{process.id} WHERE process_id IS NULL LIMIT 100; 

SELECT id FROM table_name WHERE process_id = #{process.id} FOR UPDATE; 

qui garantit que chaque fil sélectionne un ensemble unique de lignes de la table.

Espérons que cela aide.

+1

1 en utilisant LIMIT est une bonne idée –

+1

Dans cet exemple, si le script brusquement interrompu après la première mise à jour, comment voulez-vous « nettoyer » la. base de données de vieux processus? Sinon, ces 100 lignes ne seraient jamais pris en charge –

+1

Bonne question. Je règle habituellement soit la même colonne ou un ' colonne 'state' pour indiquer la réussite (dans le cadre de la transaction). Ensuite, si un processus meurt, vous pouvez définir n'importe quel process_id pour un processus non existant à NULL pour un autre processus à ramasser. Je préfère les tâches cron pour le nettoyage, mais vous pouvez également faire partie de démarrer un nouveau processus. –

0

Même si ce n'est pas la meilleure solution, comme je ne sais pas comment ignorer les lignes verrouillées, j'en sélectionne une aléatoire et j'essaie d'obtenir un verrou.

START TRANSACTION; 
SET @v1 =(SELECT myId FROM tests.table WHERE status is NULL LIMIT 1); 
SELECT * FROM tests.table WHERE [email protected] FOR UPDATE; #<- lock 

Définition d'un petit délai d'attente pour la transaction, si cette ligne est verrouillé la transaction est annulée et j'essayer un autre. Si j'obtiens le verrou, je le traite. Si (malchance) cette ligne était verrouillée, elle est traitée et le verrou est libéré avant mon délai d'attente, puis je sélectionne une ligne qui a déjà été «traitée»! Cependant, je vérifie un champ que mes processus ont défini (par exemple, statut): si l'autre transaction de processus s'est terminée correctement, ce champ me dit que le travail a déjà été fait et que je ne traite plus cette ligne. Toute autre solution possible sans transaction (par exemple, en définissant un autre champ si la ligne n'a pas d'état et ... etc.) peut facilement fournir des conditions de concurrence et des processus manqués (par exemple, un thread meurt brusquement, les données allouées sont toujours balisées, alors qu'une transaction arrive à expiration, réf. commentaire here

Hope it helps

Questions connexes