TSQL WÄHLEN Sie dann UPDATE in einer Transaktion, dann wieder AUSWÄHLEN
Bin ich wirklich Mühe mit einer Abfrage in meinem ColdFusion-Anwendung (backended zu MS SQL 2008). Ich bekomme den DB-deadlock-Fehler an dieser Transaktion:
<code>
<cftransaction>
<cfquery name="selectQuery">
SELECT TOP 20 item_id, field2, field3
FROM Table1
WHERE subject_id = #subject_ID# AND lock_field IS NULL AND
NOT EXISTS (SELECT * FROM Table2 WHERE Table2.user_ID = #user_ID# Table1.item_id = Table2.item_id)
</cfquery>
<cfquery name="updateQuery">
UPDATE Table1
SET lock_field = 1, locked_by = #user_ID#
WHERE Table1.item_id IN (#ValueList(selectQuery.item_id#)
</cfquery>
</cftransaction>
</code>
Bascially, ich habe eine Tabelle (Tabelle1), die für einen großen Schlange der wartenden Elemente. Der Benutzer "zur Kasse" - Elemente, um Ihnen eine Punktzahl. Nur ein Benutzer kann ein Element ausgecheckt zu einer Zeit. Ich brauche auf Anfrage einen block von 20 Elementen, die zu einem Zeitpunkt für einen bestimmten Benutzer. Diese Elemente können bereits überprüft werden und der Benutzer kann bereits erzielte Sie vor (daher der lock_field IST NULL-und not EXISTS-Anweisung im SELECT). Einmal habe ich bestimmt die Liste der 20 item_ids, muss ich dann update der queue-Tabelle zu markieren, die Sie als gesperrt, so dass niemand sonst prüft Sie bei der gleichen Zeit. Ich auch zurückgeben müssen, die Liste der item_ids.
Ich dachte, es funktioniert vielleicht besser, wenn ich zog diese aus einer cftransaction, um eine gespeicherte Prozedur auf dem SQL Server-Seite. Ich bin mir nur nicht sicher, ob die cftransaction Verriegelung stört irgendwie. Ich bin kein TSQL-guru, so dass etwas Hilfe würde geschätzt werden.
- Haben Sie eine
<cflock scope="application">
im Ort zu schützen Sie Ihre UPDATE-Vorgang? Auf diese Weise werden alle concurrency-Probleme sollten Weg gehen. - Das update ist Teil der cftransaction. Ich bin mir nicht sicher, ob ein cflock erforderlich ist, nicht?
- Ein cftransaction lediglich ein Rollback für jede SQL-Anweisung ausgegeben, die innerhalb es, sobald ein Fehler Auftritt. Es sperrt nicht, dass code-Abschnitt.
- Ja, aber die Verriegelung in Frage nicht-CF-variable sperren, es Datenbank-sperren. Ich bin nicht versuchen, den Zugriff/Aktualisierung der CF-vars in dieses problem.
- Es ist wahrscheinlich eine Transkription Fehler, aber Sie ' re fehlt eine Klammer in der update-query.
- Ich Stimme mit Tomalak. Sie haben vermutlich eine race-condition geht. Am besten single-thread-dieses Stück code mit CFLOCK.
- Lewis: Sie sind nicht nur sperren von Variablen den Zugriff mit <cflock> - Sie stellt sicher, dass nur ein thread kann immer Zugriff auf diesen code-Abschnitt, der zu einem bestimmten Zeitpunkt. Alle anderen threads müssen warten, bis der einen verlassen hat, den gesperrten Abschnitt. Es scheint wie ein guter Fall für single-threaded-Zugriff. Natürlich bedeutet dies die überführung einer Applikation-große, exklusive Sperre.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verwendung einer common table expression zu wählen Sie die Daten, danach update der CTE und die Ausgabe der UPDATE-Anweisung. Auf diese Weise ist alles eine einzige operation:
SELECT ... FROM (SELECT ... FROM table)
schreiben SieWITH cte AS (SELECT ... FROM TABLE) SELECT ... FROM cte
und die beiden sind identisch. Mein Beispiel kann umgeschrieben werden, mit abgeleiteten Tabellen, wie Ralph haben. Ich lieber CTE syntax wie ich finde es einfacher zu Lesen und zu befolgen.Nicht zu wissen, viel (sprich: nichts) über PHP, aber habe einige Erfahrung mit TSQL können Sie zu prüfen, ändern Sie Ihre Abfrage, um so etwas wie dieses:
Dies sollte sicherstellen, dass die Elemente, die Ihre auswählen, werden gesperrt, bis das update abgeschlossen ist.
edit: Hinzugefügt eine output-Klausel der ursprünglichen Frage wollte auch wissen, welche Zeilen aktualisiert wurden.