Jump to content

Datensatz zur Bearbeitung sperren

Empfohlene Beiträge

Hallo zusammen,

kann mir vielleicht jemand sagen, ob (und wie) es möglich ist, eine Zeile in der Datenbank zu sperren.

Das Problem ist folgendes: es läuft ein MS SQL Server 2008 R2 mit einer Datenbank und mehrere Clients greifen auf die Datenbank zu (Client-Applikation ist in C#).

Wenn nun Client1 den Artikel A1 aus der Datenbank anzeigt und bearbeitet (Bearbeitung via Textfelder etc.), so sollen für alle anderen Clients, die sich den Artikel A1 anzeigen lassen, die Textfelder zur Bearbeitung ausgeschalten (disabled) sein.

Gibt es hierfür eine sinnvolle / elegante Lösung?

Danke :-)

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen

Egal bei welcher Datenbank wenn du anfängst Zeilen selbst mit einem Lock zu versehen musst du dir auch darüber Gedanken machen wie du sie wieder frei gibst. Was ist wenn dein Programm nach dem Lock abstürzt? Was ist wenn ein Mitarbeiter auf edit klickt und dann erst mal einen Kaffee trinken geht bzw. schnell nach Hause muss? Das sind nur ein paar Dinge an die du denken musst. Zudem sollte ein solcher lock immer nur so kurz wie möglich gehalten werden!

Aus diesem Grund setzen nur wenige Programme einen Lock selbst. Sie führen intern in der DB bzw. in der Tabelle einen Versionszähler mit. Ist dieser nicht mehr gleich dem des gelesenen Zustandes kommt es zu einem Fehler der von einem Programm oder Mitarbeiter manuell gelöst werden muss. Du könntest dann z.B. einen compare zwischen den beiden Versionen anbieten und der Mitarbeiter kann dann entscheiden was richtig ist bzw. weitere Änderungen bei sich übernehmen und dann die richtige Version in die DB schreiben. Das ganze wird dann auch optimistic locking genannt.

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen
Kannst dir mal table hints (Table Hints (Transact-SQL)) und im Speziellen ROWLOCK anschauen. Vielleicht hilft das.

Kurz gesagt : Nein !

Grund, siehe weiter unten

Egal bei welcher Datenbank wenn du anfängst Zeilen selbst mit einem Lock zu versehen musst du dir auch darüber Gedanken machen wie du sie wieder frei gibst. Was ist wenn dein Programm nach dem Lock abstürzt?

Sorry, aber das ist ebenfalls schlicht falsch. Query A hält einen ReadLock auf Page xyz, --> alle anderen Prozesse warten bis Query A (das ist ein Prozess in der DB) den Lock wieder frei gibt. Über Isolation Level will hier keinen Aufsatz schreiben, aber wer with(no lock) oder read uncomitted benutzt, sollte entweder wissen was das bedeutet, oder es nicht verwenden.

Wenn jetzt Query A / Prozess A, in einen Timeout läuft, dann wird die Transaktion zurückgerollt, der Lock releast, und alle anderen Queries / Prozesse, die darauf warten dass der Lock releast wird, laufen weiter. Das ist definitiv nichts, was aus dem Frontend gesteuert werden muss / kann.

Allgemein zum Locking auf DB Ebene :

Db seitige Locks sind dafür da, zu verhindern, dass Daten verändert werden, während sie gelesen oder geschrieben werden (das kann ganz hässliche Folgen haben).

Db seitige Locks sind definitiv nicht dafür da, Business Logic zu implementieren, aka User A hat die Daten momentan im alleinigen Schreib Zugriff. Vergiss das in dem Zusammenhang ganz schnell, da tust du dir keinen Gefallen mit.

Was ich dir raten würde in diesem Fall ist, im Frontend einen Lese und einen Schreib Zugriffsmodus zu implementieren.

So kannst du einem User B im Frontend darstellen, dass er den aktuellen Datensatz nur lesen kann, weil User A gerade diesen Datensatz bearbeitet. Wenn du so etwas über Rowlocking machen würdest, dann hättest du ein Query von User A, dass den Lock hält, und ein Query von User B, dass >wartet< bis der Lock wieder frei gegeben wird.

--> User A hält lock und editiert / geht was essen, User B schreibt support ticket weil es den anschein hat dass sich die Application gehängt hat.

Du hast 2 Möglichkeiten um so ein Problem zu lösen :

1. Füge ein neues Feld in die entsprechende Tabelle ein, in der du per Update festhalten kannst, dass der Datensatz momentan bearbeitet wird. Ok, wären in der Regel 2 Felder, Feld 1 : UserID wer den Datensatz gerade bearbeitet, und Feld 2 das datum wann der Datensatz gesperrt wurde.

Das wäre eine recht einfache zu implementierende Lösung. Hat allerdings auch einen nicht unwesentlichen Nachteil.

Da du ständig rows Updatest, kannst du nicht mehr auf rowversion zurückgreifen um eventuell ein Datewarehouse zu updaten. Ich würde davon abraten falls machbar.

Möglichkeit 2 :

Nimm dir eine seperate tabelle, FK auf dem primary key deiner Tabelle die du "sperren" möchtest, und Felder für die informationen die du für den "Lock" wissen möchtest. Also "Wer", "Wann", evtl. "Warum" etc.

Das kannst du wenn das Frontend statt direkt auf Tabellen auf Stored Procedures zugreift dann auch ohne weiteres zu einem Change Tracking ausbauen bei Bedarf.

Nachteil hier wäre, dass du einen extra Join, oder NOT EXISTS (), hättest, um zu prüfen ob der Datensatz gerade gesperrt ist.

Das wären die 2 Möglichkeiten die ich sehen würde. Vergiss aber das SQL interne row / page Locking GANZ schnell bei der Fragestellung.

Wenn SilentDemise richtig verstehe, geht das auch in Richtung einer seperaten Tabelle in der dann die "gelockt von" information festgehalten wird.

bearbeitet von streffin

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen
Sorry, aber das ist ebenfalls schlicht falsch. Query A hält einen ReadLock auf Page xyz, --> alle anderen Prozesse warten bis Query A (das ist ein Prozess in der DB) den Lock wieder frei gibt. Über Isolation Level will hier keinen Aufsatz schreiben, aber wer with(no lock) oder read uncomitted benutzt, sollte entweder wissen was das bedeutet, oder es nicht verwenden.

Wenn jetzt Query A / Prozess A, in einen Timeout läuft, dann wird die Transaktion zurückgerollt, der Lock releast, und alle anderen Queries / Prozesse, die darauf warten dass der Lock releast wird, laufen weiter. Das ist definitiv nichts, was aus dem Frontend gesteuert werden muss / kann.

Du hattest aber schon gesehen das es hier um verteilte Anwendungen geht! Da schaut das ganze etwas anders aus denn du kannst deine Transaktion zwischen einem Server und einem client nur bedingt offen halten bzw. sollte man das nicht wirklich machen. Deshalb muss er sich wenn er manuell eine Zeile mit einem lock versieht sich auch drum kümmern das diese Zeile wieder frei gegeben wird. Denn den lock hat er commited und da räumt dann keine DB die ich kenne irgendwann mal wieder auf.

Ansonsten wiederholst du nur das was ich auch schon geschrieben habe.

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen

Sorry, aber nein.

Wir reden hier von MS SQL Server 2008 R2, nicht von einem abstrakten DBMS, also dürfen wir hier schon konkret auf die Eigenenheiten eingehen.

Wenn du die connection terminierst die aktuell noch eine Transaktion oder einen Lock offen hält, dann wird die Transaktion zurückgerollt, und/oder der Lock releast.

D.h. dass sofern die App ob jetzt verteilt oder nicht, die Connection killt, dann ist dein Lock so oder so flöten.

Db seitiges Locking ist schlicht das falsche für die Problemstellung.

Eventuell kam das nicht ganz rüber, ich rede von DB internem Locking. RowLock, PageLock, TableLock.

Das ist was allgemein (oder zumindest bei mir) unter Lock in einer Datenbank verstanden wird.

Das kann in anderen DBMS's anders sein, aber wir reden von einem exakt benannten DBMS

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen

Gerade der MS SQL Server bietet z.B. auch noch andere Locks an z.B. Application Locks. Hinzu kommt das per default zumindest mal im MS SQL Server es kein time out für Transaktionen gibt. Also einmal eine Transaktion aufgemacht und ein select mit read for update abgesetzt schon hast du richtig viel Spass.

Aber egal welches Datenbanksystem du verwendest es ist nie eine gute Idee innerhalb eine Datenbanktransaktion noch Userinteraktion zuzulassen. Nichts anderes ist das oben angesprochene sperren bis ich mit meiner Arbeit fertig bin.

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen

>Gerade der MS SQL Server bietet z.B. auch noch andere Locks an z.B. Application Locks.

Davon abgesehn das ich noch nie jemanden getroffen hab der das wirklich benutzen würde, und es in freier Wildbahn bisher nicht 1x sehen musste :

MSDN

Zitat : "Locks placed on a resource are associated with either the current transaction or the current session. Locks associated with the current transaction are released when the transaction commits or rolls back. Locks associated with the session are released when the session is logged out. When the server shuts down for any reason, all locks are released.

The lock resource created by sp_getapplock is created in the current database for the session. "

Preisfrage : Was passiert mit deiner Session wenn die zugehörige connection gekillt wird ?

>Hinzu kommt das per default zumindest mal im MS SQL Server es kein time out für Transaktionen gibt

Das wäre der Command timeout des connection Strings, und wenn ich nicht ganz stark irre, dann gabs da defaults auf server und database level.

(link)

Aber ja, immer noch, deine DB connection wird aus welchen Gründen auch immer geclost, dein Locking geht zum Teufel.

Ergo, Db seitiges Locking ist immer noch kein brauchbares instrument um diese BUSINESS LOGIC zu implmentieren.

Mal ganz davon abgesehen, dass ich als Programmierer doch durchaus nen etwas anderes Feedback von einer Function haben möchte, die mir datensätze updated, als eine SQL Exception, einen SQL Command Timeout, oder einfach gar nichts und die drehende Sanduhr für 5 Stunden.....

Warum in aller Welt bist du so erpicht auf DB seitigem Locking ?

Es ist Session=Connection abhängig, wie dus drehst und wendest, und schlicht und ergreifend nicht das richtige Mittel.

Wir reden von Application calls, nicht von dem was du ins Managment Studia hackst. Und sorry, wer sich ne command timeout von 0 im Frontend leistet, der hats irgendwo verdiehnt. Selbst wennd den connection string von connectionstrings.com copy pastest hast de immer noch die default db settings für den timeout.

Aber egal welches Datenbanksystem du verwendest es ist nie eine gute Idee innerhalb eine Datenbanktransaktion noch Userinteraktion zuzulassen.

da sind wir uns einig.

bearbeitet von streffin

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen
Warum in aller Welt bist du so erpicht auf DB seitigem Locking ?

Es ist Session=Connection abhängig, wie dus drehst und wendest, und schlicht und ergreifend nicht das richtige Mittel.

Du hast meine Beiträge auch gelesen oder? Ich habe nie auch nur mit einem Wort davon gesprochen das es DB seitig etwas locken soll. Ich habe lediglich drauf hingewiesen, wenn er so etwas machen will, was ja grundsätzlich erstmal die DB zulassen würde, er aufpassen muss was er da macht. Mehr habe ich nicht gesagt ich habe weder Werbung dafür gemacht noch sonst irgendwie ihn dazu gedrängt.

Da du hier sehr gerne auf MSDN verlinkst hier mal ein Link auf das von mir angesprochenen per default nicht vorhandene LOCK_TIMEOUT von Transaktionen. Deadlocking

By default, SQL Server transactions do not time out, unless LOCK_TIMEOUT is set.

Das bedeutet eben SELECT mit einem read for update und dann Kaffee trinken gehen ist eine doofe Idee. Sich dann darauf zu verlassen das die Connection zur DB das Problem irgendwann mal beseitigt ist noch eine viel schlechtere Idee. Denn das funktioniert auch nur dann wenn du von deinem Client direkt eine connection zur DB auf machst wenn du vom Client deine Anfragen erst an einem Webservice oder ähnliches sendest hast du noch nicht mal mehr das Connection Timeout was dich retten kann.

Das ist in dem Thema dann auch mein letzter Beitrag! Denn ich habe schlicht und ergreifend nichts falsches geschrieben auch wenn mir hier etwas anderes unterstellt wird.

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen
Gibt es hierfür eine sinnvolle / elegante Lösung?

Ich fasse die Antworten mal zusammen: Nein, gibt es nicht und ist auch nicht praktikabel. Um Lost Updates zu verhindern kannst Du optimistisches Locking verwenden und dem User zumindest darauf hinweisen, dass es neuere Änderungen gibt.

Diesen Beitrag teilen


Link zum Beitrag
Auf anderen Seiten teilen

Nimm an der Diskussion teil

Du kannst jetzt hier posten und Dich später registrieren. Wenn Du bereits über eine Konto verfügst, melde Dich jetzt an, um mit Deinem Konto zu posten.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.


Fachinformatiker.de, 2020 SE Internet Services

fidelogo_small.png

if_icon-6-mail-envelope-closed_314900.pnSchicken Sie uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App


Get it on Google Play

Kontakt

Hier werben?
Oder senden Sie eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...

Wichtige Information

Fachinformatiker.de verwendet Cookies. Mehr dazu in unserer Datenschutzerklärung