t.ony Geschrieben 2. Dezember 2010 Teilen Geschrieben 2. Dezember 2010 Hallo, folgende Situation: Anwender1 lässt sich die Daten anzeigen, wählt nen Datensatz aus (geschieht alles über ne GUI) und will den nun ändern. Jetzt will ich vermeiden das Anweder2 den Datensatz genau in diesem Moment löscht. Weil kann ja sein, dass Anwender1 unheimlich langsam ist, zwar schon im Änderungsmodus, Anweder2 aber doch schneller war. Ich dachte ich könnte das irgendwie mit RowLock lösen, dass ich quasi den Datensatz wenn der Anwender1 auf "Bearbeiten" klickt einfach nochmal aus der DB lese und sperre. So lange wie Anwender1 dann brauch zum bearbeiten kann ihn dann kein andere bearbeiten und auch nicht löschen. Ist das irgendwie möglich mit MS SQL? Wenn ich den Datensatz mit "Select * from tabelle_xyz with(rowlock) where id=1" ist hole bringt mir das ja nix, weil das ja nur für diese winzig kurze zeit gesperrt ist. Jemand ne Idee? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
streffin Geschrieben 3. Dezember 2010 Teilen Geschrieben 3. Dezember 2010 füg 2 neue spalten in die tabelle ein. [locked_for] <- der user der den datensatz aktiv grade "hat" [locked_at <- timestamp wann der datensatz gelockt wurde. Bau im Frontend ein, dass ein User, der erste, den Datensatz "schreibgeschützt" hat, und bau auch ein, dass nach x minuten, er den Schreibschutz nicht mehr inne hat. Viel Spass sowas nachträglich einzubauen, aber in irgendeiner weise musst du sowas einbauen, weil du von der Datenbank an sich kein Event geschmissen bekommen kannst, wenn sich ein Datensatz geändert hat. D.h. in dem Moment wo 2 User gleichzeitig einen Datensatz laden und verändern können, hast du ein tierisches Problem, weil die 2 sich dann gegenseitig die Änderung überschreiben. Wie gesagt have fun, sowas nachträglich is hässlich und aufwendig. Gruß Sven Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
dr.dimitri Geschrieben 3. Dezember 2010 Teilen Geschrieben 3. Dezember 2010 Die Lösung von streffin ist leider nicht ganz wasserdicht, denn wenn Du prüfst, ob deine neue Spalte schon gefüllt ist, kann diese schon aktualisiert aber noch nicht committet sein. Damit überschreibst Du kurze Zeit später den Wert den die andere Session reingeschrieben hat. Was passiert, wenn die Rechnerzeit nicht stimmt oder wenn sich ein User mehrfach angemeldet hat wollen wir hier gar nicht weiter vertiefen. Grundsätzlich gibt es zwei unterschiedliche Herangehensweisen: Das optimistische und das pessimistische Locking. Pessimistisches Locking wie Du es vorhast hat einen entscheidenden Nachteil: geht der Anwender in die Mittagspause, so sperrt er für diese Zeit den Datensatz (und ist sich dessen vielleicht nicht mal bewußt). Die Implementierung ist allerdings recht einfach. Es gibt beim SELECT die Option FOR UPDATE: SELECT ... FROM ... WHERE ... FOR UPDATE Damit sind die selektierten Datensätze bis zum Ende der Transaktion exclusiv gelockt. Die elegantere Methode ist das optimistische Locking. Hierzu fügst Du ein weiteres Feld in jde Tabelle ein, für die Du dies implementieren möchtest. Idealerweise ein Timestamp Feld, das auf ms Ebene anzeigt. Wird der Datensatz geladen, so selektierst Du das Feld und merkst dir den Wert im Programm. Speichert der Anwender seine Daten, so ergänzt Du Deinen Update wie folgt: UPDATE ... SET ...,dstimestamp=aktueller_timestamp WHERE id=... AND dstimestamp=der_vorher_gemerkte_wert Läuft der Update durch und ändert einen Datensatz, ist alles ok. Ändert der Update aber 0 Zeilen, dann wurde das Timestamp Feld schon von einer anderen Session geändert und dementsprechend dürfen diese Daten nicht ohne Rückmeldung überschrieben werden. Andere Möglichkeiten das sauber hinzubekommen gibt es nicht. Dim Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Reinhold Geschrieben 3. Dezember 2010 Teilen Geschrieben 3. Dezember 2010 Moin, ich kann dem Doktor da nur zustimmen, die optimistische Variante mit dem Timestamp-Feld ist handlich und praktikabel und reicht für uns Kassenpatienten völlig aus. Die Implementierung ist allerdings recht einfach. Es gibt beim SELECT die Option FOR UPDATE: SELECT ... FROM ... WHERE ... FOR UPDATE Damit sind die selektierten Datensätze bis zum Ende der Transaktion exclusiv gelockt. Bist du dir da sicher, das das so mit MS-Sql geht? Mein MS-SQL-Server 2005 versteht die Klausel "for update" jedenfalls nicht. Ich lerne da aber gern was dazu. Reinhold Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
dr.dimitri Geschrieben 3. Dezember 2010 Teilen Geschrieben 3. Dezember 2010 Bist du dir da sicher, das das so mit MS-Sql geht? Mein MS-SQL-Server 2005 versteht die Klausel "for update" jedenfalls nicht. Ich lerne da aber gern was dazu. Reinhold Hmm erwischt. Da hab ich mal wieder Oracle auf auf andere Datenbanken übertragen ohne nachzuforschen ob es das dort gibt. Dim Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Reinhold Geschrieben 3. Dezember 2010 Teilen Geschrieben 3. Dezember 2010 Ah, ok. Es war auch weder böse noch süffisant gemeint, nicht das du denkst, ich hätte mir nur meine Ohren verdienen wollen... *hehe Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Corto -sX- Geschrieben 3. Dezember 2010 Teilen Geschrieben 3. Dezember 2010 wenn man "mssql select for update" in google hineinwirft sagt es : select <columns> from <table> WITH [TABLOCK] -- (or ROWLOCK, or HOLDLOCK ) scheint also auch in mssql das gleiche vorgehen, nur eben andere Syntax (falls mal jemand hier landet) @Threadersteller: versuch mal den Holdlock - das wird das sein was du suchst.. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
t.ony Geschrieben 6. Dezember 2010 Autor Teilen Geschrieben 6. Dezember 2010 mh leider hilft mir auch holdlock nicht weiter... hatte ich natürlich auch direkt ausprobiert. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
dr.dimitri Geschrieben 6. Dezember 2010 Teilen Geschrieben 6. Dezember 2010 Hmm wenn ich die Doku richtig verstanden hab, dann wäre aber ROWLOCK Dein Wunschkandidat. Dim Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Goos Geschrieben 7. Dezember 2010 Teilen Geschrieben 7. Dezember 2010 mh leider hilft mir auch holdlock nicht weiter... hatte ich natürlich auch direkt ausprobiert. Doch doch, HOLDLOCK hilft dir weiter. Du musst natürlich darauf achten, auch eine entsprechende Transaktion zu setzen. Alternativ zum HOLDLOCK Table Hint kannst du auch den Transaction Isolation Level für diese Transaktion auf SERIALIZABLE setzen. Der ROWLOCK Table Hint allein wird in deinem Fall nicht funktionieren. Du kannst allerdings über ROWLOCK in Verbindung mit XLOCK eine exklusive Sperre auf dem Datensatz setzen (Das verhindert für andere Benutzer dann aber auch die Anzeige des Datensatzes). Goos Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.