Ich kenne knex nicht im Detail und nach einer kurzen Suche unterstützt knex derzeit nicht die Verwendung von "limit" für Update-Anweisungen, also nur eine Beschreibung des allgemeinen Ansatzes.
Führen Sie zuerst eine Aktualisierung für die Zeile durch, die den Kriterien entspricht, und wählen Sie dann diese aktualisierte Zeile aus.
Führen Sie also zuerst eine Aktualisierungsoperation durch, die die aktuelle Benutzer-ID der ersten unverarbeiteten Zeile zuweist, der entweder kein Benutzer zugewiesen ist oder der bereits derselbe Benutzer zugewiesen ist:
update rows
set assignedTo = user.id
where assignedTo=0 or assignedTo=user.id
order by createdAt asc
limit 1
Ich denke, es kann mit Knex mit einer Rohabfrage so funktionieren, aber ich habe das nicht versucht:
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid order by createdAt asc limit 1', {userid: user.id})
Dadurch wird nach der ersten (am frühesten erstellten) Zeile gesucht, die nicht zugewiesen oder bereits demselben Benutzer zugewiesen ist, und dann diesem Benutzer zugewiesen. Dies geschieht in einem Rutsch.
Sie können dann nach der dem Benutzer zugewiesenen Zeile suchen:
const notProcessed = await knex('rows')
.select('*'')
.whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
.orderByRaw('createdAt asc')
.first();
Beachten Sie, dass wir jetzt explizit nur nach einer Zeile suchen, die dem Benutzer bereits zugewiesen ist.
Kombiniert
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();
Offensichtlich brauchen Sie die Auswahl nicht, wenn Sie nicht sofort mit der Zeile arbeiten möchten.
Das Problem ist, dass Sie sich bei der gleichzeitigen Bearbeitung mehrerer Anfragen mehrere Instanzen des Codes vorstellen müssen, die gleichzeitig parallel ausgeführt werden. Mit Ihrem ursprünglichen Code könnten also zwei Anfragen gleichzeitig Ihre Auswahl treffen, bevor eine von ihnen eine Aktualisierung durchführt. Also wird für beide die gleiche Zeile zurückgegeben.
Durch die sofortige Aktualisierung der Zeile innerhalb der Anweisung stellt die Datenbank sicher, dass sie nicht dieselbe Zeile sehen, selbst wenn zwei Anweisungen parallel ausgeführt werden.
Ein alternativer Lösungsansatz wäre die Verwendung eines Mutex (wie z. B. async-mutex ) um Ihren ursprünglichen Code, um sicherzustellen, dass Ihr ursprünglicher Auswahl- und Aktualisierungsvorgang atomar ist (erfolgt auf einmal), aber dies wird höchstwahrscheinlich die Antwortzeit Ihrer Anwendung erhöhen, da in einigen Situationen ein Vorgang zur Verarbeitung von Anforderungen auf einen anderen warten muss eine zum Fortfahren.