Neznám knex podrobně a z rychlého vyhledávání knex v současné době nepodporuje použití "limit" na aktualizačních příkazech, takže pouze popis obecného přístupu.
Nejprve proveďte aktualizaci řádku, který odpovídá kritériím, a poté vyberte aktualizovaný řádek.
Nejprve tedy proveďte operaci aktualizace, která přiřadí aktuální ID uživatele prvnímu nezpracovanému řádku, který buď nemá přiřazeného žádného uživatele, nebo již má přiřazeného stejného uživatele:
update rows
set assignedTo = user.id
where assignedTo=0 or assignedTo=user.id
order by createdAt asc
limit 1
Myslím, že to může fungovat takto s knex pomocí nezpracovaného dotazu, ale nezkoušel jsem to:
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid order by createdAt asc limit 1', {userid: user.id})
Toto vyhledá první řádek (nejprve vytvořenýAt), který není přiřazen nebo je již přiřazen stejnému uživateli, a poté tohoto uživatele přiřadí. To se stane jedním tahem.
Poté můžete vyhledat řádek přiřazený uživateli:
const notProcessed = await knex('rows')
.select('*'')
.whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
.orderByRaw('createdAt asc')
.first();
Všimněte si, jak nyní explicitně hledáme pouze řádek již přiřazený uživateli.
Kombinovaný
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid order by createdAt asc limit 1', {userid: user.id})
const notProcessed = await knex('rows')
.select('*'')
.whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
.orderByRaw('createdAt asc')
.first();
Pokud nechcete s řádkem pracovat okamžitě, výběr samozřejmě nepotřebujete.
Problém je v tom, že když se zpracovává více požadavků současně, musíte si představit více instancí kódu běžících ve stejnou dobu paralelně. Takže s vaším původním kódem mohou dva požadavky provést váš výběr současně, než kterýkoli z nich provede aktualizaci. Oběma se tedy vrátí stejný řádek.
Okamžitou aktualizací řádku v příkazu, i když dva příkazy běží paralelně, databáze zajistí, že nevidí stejný řádek.
Alternativním přístupem k řešení by bylo použití mutexu (jako např. async-mutex ) kolem vašeho původního kódu, abyste se ujistili, že vaše původní operace výběru a aktualizace je atomická (proběhne najednou), ale to s největší pravděpodobností prodlouží dobu odezvy vaší aplikace, protože v některých situacích bude muset jedna operace zpracování požadavku čekat na druhou. jeden na pokračování.