3 Stimmen

Wie kann ich sicher aus einem DBMS aussteigen, wenn Datensätze gesperrt sind?

Ich bin ein Hobbyprogrammierer, mache es aber schon eine Weile. Ich schreibe eine kleine Anwendung zur Dokumentenverwaltung für den Gebrauch bei der Arbeit (in c#). Wenn ein Benutzer einen Datensatz öffnet, aktualisiere ich ihn, um anzuzeigen, dass er derzeit gesperrt ist.

Was ich mir nicht sicher bin, ist, wie ich sicherstellen kann, dass die Datenbank aktualisiert wird, wenn die Anwendung unsicher beendet wird (z. B. wenn der Computer unerwartet heruntergefahren wird). Außerdem, wie sollte ich sie aktualisieren, wenn die Anwendung beendet wird, indem der Benutzer den Computer herunterfährt? Ich möchte nur sicherstellen, dass keine Datensätze als gesperrt markiert werden, wenn sie von niemandem angesehen werden.

2voto

Tim Punkte 5351

So wird dies normalerweise mit SQL Server gemacht. Von Entwicklern ausgegebene "Datensatzsperren" sind für die Client-Server-Architektur nicht relevant. Sie verwechseln die gemeinsame Dateiarchitektur mit der Client-Server-Architektur.

Stellen Sie sicher, dass die Tabelle eine Zeitstempelspalte hat (die automatisch vom Datenbankmotor aktualisiert wird).

Lesen Sie die Zeile ein, die Sie bearbeiten möchten. Legen Sie den Zeitstempel aus der Zeile in eine Variable.

Das Update-Statement sieht so aus:

update myTable
set col = {ein Wert}
where id = {Ihre ID}
UND
zeitstempelspalte = {der Zeitstempel, den die Zeile hatte, als Sie sie eingelesen haben}

Wenn jemand die Zeile seit Ihrem Einlesen geändert hat, wird sie einen anderen Zeitstempel haben und es wird kein Datensatz Ihren WHERE-Bedingungen entsprechen, sodass Ihr Update fehlschlägt. Dann können Sie entscheiden, was zu tun ist.

Sie können den Stecker des Client-PCs ziehen, wenn Sie SQL-Server (oder Oracle oder jede echte Client-Server-Architektur) verwenden, ohne dass sich dies negativ auf den Server auswirkt.

1voto

Andrew M Punkte 8769

In C# können Sie try-catch-finally-Blöcke verwenden und Ihre Bereinigung im finally durchführen. (Was egal was passiert ausgeführt werden sollte).

Sie könnten praktisch das Gleiche erreichen, indem Sie eine Klasse erstellen, die IDisposable implementiert, die das Schloss erhält und es freigibt, wenn die Dispose-Methode aufgerufen wird. Dann immer, wenn Sie diese Klasse verwenden (das Schloss erhält), fügen Sie einen using-Block hinzu

using (RecordLockingThing myThing = new RecordLockingThing())
{
    //DoStuff
}
//Jetzt ist myThing außerhalb des Gültigkeitsbereichs und wurde entsorgt.

Stellen Sie einfach sicher, dass Ihre RecordLockingThing das Schloss korrekt und sicher in der Dispose-Methode freigibt.

Eine andere Strategie könnte sein, Datensätze nicht zu markieren, um sie zu sperren, wenn sie geöffnet werden, sondern sie stattdessen als bearbeitet zu markieren (oder eine Revisionsnummer zu erhöhen). Dann können Sie mehr als eine Person den Datensatz öffnen lassen. Wenn jemand eine Bearbeitung einreicht, lassen Sie sie auch die Revisionsnummer einreichen. Wenn sie übereinstimmt, übernehmen Sie die Bearbeitung und erhöhen die Revisionsnummer, andernfalls melden Sie eine "Mid-Air-Kollision" und verwerfen die Bearbeitungen (nicht sehr benutzerfreundlich) oder versuchen lassen den Benutzer die Datensätze zusammenzuführen.

Wenn Bearbeitungen im Vergleich zu Lesevorgängen relativ selten sind, ist die zweite Strategie in der Praxis nützlicher, da Sie einem Benutzer niemals verwehren, sich zumindest einen Datensatz anzusehen, und es kein Risiko von verwaisten Sperren gibt.

0voto

Marc Gravell Punkte 970173

Um Probleme mit unerwarteten Abschaltungen zu behandeln, würde ich normalerweise jedem logischen Schloss ein Ablaufdatum geben; das könnte bedeuten (zum Beispiel) dass Sie eine LockOwnerId und eine LockExpiry Spalte benötigen, aber das ist normalerweise kein Problem. Ihre App kann das Schloss immer verlängern, wenn der Benutzer sich noch auf einem Bildschirm befindet, aber das bedeutet, dass wenn die Maschine einfach vom Netzwerk getrennt wird, der Datensatz in ein paar Minuten implizit wieder verfügbar wird. Die andere Option ist es, Schlüsselanwendern zu erlauben, Schlösser zu zerstören.

Bezüglich der Beendigung der App durch den Benutzer; verfolgen Sie einfach, welche Schlösser Sie haben und entfernen Sie sie ;p

0voto

Stefan P. Punkte 9451

Ich hatte ein ähnliches Problem mit einer DMS-App, auf der Serverseite habe ich ein Session-Objekt verwendet, eine Sammlung der aktiven Benutzer, jeder Client aktualisiert das Session-Objekt alle 5 Minuten. Wenn eine Zeile gesperrt ist und der Benutzer, der sie gesperrt hat, nicht mehr im Session-Objekt ist, wird sie freigegeben. Für dieses Entsperren führe ich auf der Serverseite einen Hintergrundthread aus, der alle Minuten nach gesperrten Zeilen sucht.

0voto

Damien_The_Unbeliever Punkte 227101

Ich bin überrascht, dass niemand sp_getapplock und dessen Verwandte erwähnt zu haben scheint. Wenn Sie eine einzelne Verbindung zum Server offen halten (und der Lock von der Sitzung und nicht von der Transaktion besessen wird), wird der Lock aufrechterhalten. Wenn die Verbindung unterbrochen wird (z. B. durch ein Abstürzen des Client-Rechners), dann werden - wie bei allen internen Locks in SQL Server - die Locks freigegeben.

Im Wesentlichen handelt es sich um einen Weg, SQL Server dazu zu bringen, die gleichen Sperrmechanismen zu verwenden, die er intern für Ihre Anwendungszwecke verwendet.

Wie gesagt, ein kleines Ärgernis dabei ist jedoch, dass Sie eine Verbindung zum Server offen halten müssen. Daher ist es vielleicht eher für bis zu 50 Clients geeignet, als wenn Tausende von Clients beteiligt sind. Ich möchte auch noch eine weitere Einschränkung hinzufügen - ich habe kein Produktionssystem mit diesen Einrichtungen erstellt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X