Il peut être utile de regarder comment cette requête est réellement exécutée par MySQL :
select * from tbl_codes where available = 1 order by rand() limit 1 for update
Cela lira et triera toutes les lignes qui correspondent à WHERE
condition, générer un nombre aléatoire en utilisant rand()
dans une colonne virtuelle pour chaque ligne, triez toutes les lignes (dans une table temporaire) en fonction de cette colonne virtuelle, puis renvoyez les lignes au client à partir de l'ensemble trié jusqu'à la LIMIT
est atteint (dans ce cas un seul). Le FOR UPDATE
affecte le verrouillage effectué par l'intégralité de l'instruction pendant son exécution, et en tant que telle, la clause est appliquée lorsque les lignes sont lues dans InnoDB , pas au fur et à mesure qu'ils sont renvoyés au client.
Mis à part les implications évidentes sur les performances de ce qui précède (c'est terrible), vous n'obtiendrez jamais un comportement de verrouillage raisonnable.
Réponse courte :
- Sélectionnez la ligne souhaitée en utilisant
RAND()
ou toute autre stratégie que vous aimez, afin de trouver laPRIMARY KEY
valeur de cette ligne. Par exemple :SELECT id FROM tbl_codes WHERE available = 1 ORDER BY rand() LIMIT 1
- Verrouillez la ligne que vous voulez en utilisant sa
PRIMARY KEY
seulement. Par exemple :SELECT * FROM tbl_codes WHERE id = N
J'espère que cela aide.