Ich habe eine gespeicherte Prozedur, die im Grunde genommen Werte aus einer Tabelle auswählt und in eine andere einfügt, eine Art Archivierung. Ich möchte vermeiden, dass mehrere Personen dies gleichzeitig tun.
Während diese Prozedur ausgeführt wird, möchte ich nicht, dass jemand anderes sie starten kann. Ich möchte jedoch nicht, dass die andere Person die Prozedur ausführt, nachdem ich damit fertig bin.
Ich möchte, dass die andere Person, die versucht, es zu starten, einen Fehler erhält, während ich die Prozedur ausführe.
Ich habe versucht, sp_getapplock zu verwenden, kann es jedoch nicht schaffen, die Person vollständig daran zu hindern, die Prozedur auszuführen.
Ich habe auch versucht, die Prozedur mit sys.dm_exec_requests zu finden und die Prozedur zu blockieren, obwohl dies funktioniert, denke ich, dass es nicht optimal ist, da ich auf einigen Servern nicht die Berechtigung habe, sys.dm_exec_sql_text (sql_handle) auszuführen.
Was ist der beste Weg für mich, dies zu tun?
quelle
Antworten:
Um die Antwort von @ Tibor-Karaszi zu ergänzen, führt das Festlegen eines Sperrzeitlimits nicht zu einem Fehler (ich habe eine PR für die Dokumente eingereicht). sp_getapplock gibt nur -1 zurück, daher müssen Sie den Rückgabewert überprüfen. Also so:
quelle
Verwenden Sie sp_getapplock am Anfang des Prozesses und setzen Sie ein Sperrzeitlimit auf einen sehr niedrigen Wert. Auf diese Weise erhalten Sie eine Fehlermeldung, wenn Sie blockiert sind.
quelle
Eine andere Möglichkeit besteht darin, eine Tabelle zu erstellen, um den Zugriff auf die Prozedur zu steuern. Das folgende Beispiel zeigt eine mögliche Tabelle sowie eine Prozedur, die sie verwenden könnte.
quelle
IsLocked
in diesem Fall den Status auf 0 zurücksetzen ? Ich bin auch neugierig auf Ihre VerwendungCOALESCE
hier. Kann@@ROWCOUNT
nach Aussagen wie null seinUPDATE
? Schließlich, nur ein kleiner Trottel, warumTHROW
in diesem speziellen Fall ein Semikolon vor die Aussage setzen?Ich denke, Sie versuchen, das Problem auf falsche Weise zu lösen. Was Sie wollen, ist ein Höchstmaß an Schutz der Datenbankkonsistenz. Wenn zwei Personen gleichzeitig eine gespeicherte Prozedur ausführen, kann die Datenbankkonsistenz verletzt werden.
Zum Schutz vor verschiedenen Arten von Datenbankinkonsistenzen verfügt der SQL-Standard über vier Transaktionsisolationsstufen:
Der SQL-Standard verwendet jedoch einen auf Sperren basierenden Ansatz für diese Datenbankinkonsistenzen. Aus Leistungsgründen verwenden viele Datenbanken einen auf Snapshot-Isolation basierenden Ansatz, der im Wesentlichen folgende Ebenen aufweist:
Die Transaktionsstornierungen in diesen auf Snapshot-Isolation basierenden Datenbanken klingen möglicherweise besorgniserregend, aber andererseits bricht jede einzelne Datenbank eine Transaktion aufgrund eines Deadlocks ab, sodass jede vernünftige Anwendung ohnehin in der Lage sein muss, eine Transaktion erneut zu versuchen.
Was Sie wollen, ist die Isolationsstufe SERIALIZABLE : Sie stellt sicher, dass jede parallele Ausführung der Transaktionen auch zu einem guten Zustand führt, wenn unabhängig voneinander nacheinander ausgeführte Transaktionen zu einem guten Zustand führen. Glücklicherweise hat Michael Cahill in seiner Dissertation herausgefunden, wie die SERIALIZABLE- Isolationsstufe mit geringem Aufwand von Snapshot-isolierten Datenbanken unterstützt werden kann.
Wenn bei Verwendung einer SERIALIZABLE- Isolationsstufe in einer isolierten Snapshot-Datenbank zwei Personen gleichzeitig versuchen, die gespeicherte Prozedur auszuführen und sich gegenseitig auf die Zehen treten, wird eine der Transaktionen abgebrochen.
Unterstützt SQL Server nun wirklich die Isolationsstufe SERIALIZABLE (anstatt die Snapshot-Isolation hinter dem Schlüsselwort SERIALIZABLE zu maskieren )? Ehrlich gesagt weiß ich nicht: Die einzige mir bekannte Datenbank, die dies unterstützt, ist PostgreSQL.
Obwohl ich keine SQL Server-spezifischen Ratschläge gegeben habe, veröffentliche ich diese Antwort dennoch, da Benutzer von PostgreSQL und Benutzer anderer Datenbanken, die einen Wechsel zu PostgreSQL in Betracht ziehen können, von meiner Antwort profitieren können. Benutzer von Nicht-PostgreSQL-Datenbanken, die nicht zu PostgreSQL wechseln können, können ihren bevorzugten Datenbankanbieter unter Druck setzen, eine echte SERIALIZABLE- Isolationsstufe anzubieten .
quelle
Mir ist klar, dass das „echte“ Problem komplexer sein kann.
Falls dies nicht der Fall ist: Wenn Sie Ihre Archivierung mit Einfüge- und / oder Aktualisierungsauslösern durchführen, können Sie das Problem vermeiden, das Sie lösen möchten.
Hoffe das hilft,
-Chris C.
quelle
the 'real' problem may be more complex
. Falls dies nicht der Fall ist, sind Trigger eine gute Lösung. Außerdem ist es wahrscheinlich einfacher zu testen und zu warten, da es sich um eine Funktion der Datenbank handelt und nicht um eine benutzerdefinierte Lösung.