Sperre auf Datensatzebene

Sperre auf Datensatzebene

am 13.09.2006 22:43:08 von punkmuckel

hey leute!
folgendes problem:
eine tabelle, welche auf einem ms sql server 2005 liegt soll sowohl
über access direkt (odbc verbindung, keine formulare etc, es wird
direkt auf der verknüpften tabelle gearbeitet) als auch über ein in
php implementiertes webinterface bearbeitet werden. natürlich soll
verhindert werden, dass datensätze über das webinterface doppelt
bearbeitet werden oder das im webinterface ein datensatz geöffnet wird
und in der zwischenzeit wird er auf der access datenbank bearbeitet
etc.

beim webinterface werden zuerst alle datensätze mit einem select
geholt, der user ändert sie in der eingabemaske und erst beim
speichern (user klickt auf einen button im webinterface) wird das
update durchgeführt.

hab das ganze mit begin bzw commit transaction mit einem dummy-update
versucht, aber abgesehen davon das es sicher nicht die lösung des
problems ist hat es auch nicht sauber funktioniert.

lange rede kurzer sinn:
gibt es eine möglichkeit, einen datensatz schon beim select zu
sperren, sodass andere benutzer ihn nicht mehr bearbeiten können?

es wäre vor allem wichtig, dass eingaben, welche im webinterface
durchgeführt werden nicht aufgrund von zwischenzeitlicher änderungen
in der datenbank neu eingegeben werden müssen oder ähnliches.

folgende isolation levels habe ich schon gesetzt:
alter database Test
set ALLOW_SNAPSHOT_ISOLATION ON

alter database Test
set READ_COMMITTED_SNAPSHOT ON

danke

Re: Sperre auf Datensatzebene

am 13.09.2006 23:46:49 von Andreas Scherbaum

punkmuckel wrote:
>
> lange rede kurzer sinn:
> gibt es eine möglichkeit, einen datensatz schon beim select zu
> sperren, sodass andere benutzer ihn nicht mehr bearbeiten können?

Ja.
Das löst dein Problem aber nicht.

Bei dir schaut der Ablauf so aus: eine Anfrage selected und blockiert
damit die Daten, was durchaus funktioniert. Sobald diese Anfrage jedoch
abgeschlossen ist, werden die Locks und die Daten wieder freigegeben.
Zu einem beliebigen späteren Zeitpunkt kommt jetzt ein weiterer Request
vom Webinterface, der das Update durchführen will ... dieser Request ist
jedoch von dem vorherigen völlig unabhängig und es gibt daher auch den
Lock nicht mehr.


> es wäre vor allem wichtig, dass eingaben, welche im webinterface
> durchgeführt werden nicht aufgrund von zwischenzeitlicher änderungen
> in der datenbank neu eingegeben werden müssen oder ähnliches.

Mir fällt keine konkrete Lösung ein, wie man so etwas ohne einen
Applicationserver, der einen Lock ständig halten kann, lösen kann.

Als Workaround fällt mir ein, das man den Inhalt der Zeile beim Start
der Bearbeitung in der Session speichert und dann beim Schreiben noch
mal den Lock holt, prüft, ob der Inhalt noch dem in der Session gleicht
und eine entsprechende Fehlerbehandlung durchführt.
Vielleicht hat hier jemand noch eine bessere Idee?


> folgende isolation levels habe ich schon gesetzt:

Das hilft alles aus oben beschriebenem Grund nicht.


Bye

--
Andreas 'ads' Scherbaum
Failure is not an option. It comes bundled with your Microsoft product.
(Ferenc Mantfeld)

Re: Sperre auf Datensatzebene

am 14.09.2006 00:11:26 von Axel Schwenke

Andreas Scherbaum wrote:
> punkmuckel wrote:
>>
>> lange rede kurzer sinn:
>> gibt es eine möglichkeit, einen datensatz schon beim select zu
>> sperren, sodass andere benutzer ihn nicht mehr bearbeiten können?
>
> Ja.
> Das löst dein Problem aber nicht.

ACK.

Nicht nur, daß LOCKs an eine aktive Datenbank-Verbindung gebunden sind,
man *will* auch Datensätze nicht so lange sperren, bis der Benutzer vom
Mittagessen/der Rauchpause/aus dem Urlaub wieder zurück gekommen ist.
Von "versehentlich" geschlossenen oder abgestürzten Applikationen ganz
zu schweigen.

> Als Workaround fällt mir ein, das man den Inhalt der Zeile beim Start
> der Bearbeitung in der Session speichert und dann beim Schreiben noch
> mal den Lock holt, prüft, ob der Inhalt noch dem in der Session gleicht
> und eine entsprechende Fehlerbehandlung durchführt.

Ziemlich genau so macht man das. Heißt "optimistic locking". Und hat
mit Locking im Datenbank-Sinn nichts zu tun.

> Vielleicht hat hier jemand noch eine bessere Idee?

Typischerweise verwendet man eine Seriennummer pro Datensatz, die bei
jeder Änderung inkrementiert wird. Wenn ein Datensatz zur Bearbeitung
"geöffnet" wird, merkt man sich die aktuelle Nummer. Wenn die beim
UPDATE nicht mehr die gleiche ist, hat jemand anderes in der
Zwischenzeit geschrieben und man muß evtl. Konflikte auflösen (bzw. vom
Anwender auflösen lassen). Dafür *kann* es nützlich sein, wenn man die
alten Daten kennt. Dann könnte man bspw. konkurrierende Änderungen
zulassen, wenn die sich nicht überschneiden (Nutzer A ändert andere
Felder als Nutzer B).

Die Art der Konfliktauflösung hängt aber sehr von der spezifischen
Aufgabenstellung ab.


XL