Laden...

Speichern von unveränderten Daten

Erstellt von carl vor 8 Jahren Letzter Beitrag vor 8 Jahren 2.021 Views
C
carl Themenstarter:in
22 Beiträge seit 2011
vor 8 Jahren
Speichern von unveränderten Daten

Mal eine allgemeine Frage (Ich hoffe es passt hier rein)

Wenn zwei User A und B auf verschiedenen Clients gleichzeitig den gleichen Datensatz aufrufen, kann es zu der folgenden Situation kommen:

User A ändert alle (!) Eigenschaften des Datensatzes und speichert als erstes. Alle veränderten Werte sind nun in der Datenbank.

Einige Minuten später ändert User B nur eine (!) Eigenschaft des Datensatzes und speichert.

Beim Speichern von User B stellt die Server Applikation fest, das nicht nur eine, sondern alle Werte unterschiedlich zur Datenbank sind. Im Ergebnis werden alle Änderungen von User A überschrieben und nur die Änderung von User B bleibt bestehen.

Wie handhabt ihr das in euren Anwendungen? Teilt ihr dem Server mit, welche Änderungen vom Client vorgenommen wurden? Was ist die gängige Praxis?

Rein philosophisch könnte man argumentieren, das User B ja alle Eigenschaften im Blick hatte, sie für richtig befunden hatte und das es deshalb richtig ist, alles zu überschreiben.....hmm.

C
2.121 Beiträge seit 2010
vor 8 Jahren

Genauso philosophisch wäre es aber zu sagen, A hatte ja auch alles im Blick und wollte es anders speichern als B 😃
überschreiben halte ich für gefährlich. A geht davon aus dass seine Werte gespeichert sind und handelt entsprechend. Das gibt nur Chaos.

In deinem Fall könntest du dem Datensatz einen eindeutigen Stempel aufdrücken, der Datentyp TIMESTAMP eignet sich dafür. Ein solches Feld wird bei jedem Schreibvorgang automatisch geändert. Damit hast du eine Markierung, mit der erkannt werden kann ob der Datensatz geändert wurde.

Dein Programm lädt dieses Feld zusammen mit allen anderen Feldern mit. Beim schreiben von Änderungen prüft dein UPDATE Statement ob der Wert noch der selbe ist wie beim Laden. Wenn nicht bedeutet das ein anderer hat die Daten geändert. Dann muss man den Benutzer drauf hinweisen.

C
carl Themenstarter:in
22 Beiträge seit 2011
vor 8 Jahren

Danke für Deine Antwort. Genau so hatte ich es mir auch vorgestellt. Alle meine Datensätze haben mehrere TimeStamps (CreatedDateTime, ChangedDateTime...)

Sobald der User speichern drückt:

"Sie möchten den Datensatz XYZ speichern. Dieser hat sich zwischenzeitlich geändert. Möchten Sie fortfahren und speichern oder die aktuellen Daten laden?"

...sowas in der Art.

Selbstverständlich könnte man das auch weglassen, den User nicht belästigen und der Server-Applikation mitteilen, welche Eigenschaften vom User geändert wurden.

Was mich wirklich interessiert ist, wie das in "grossen" ERPs gelöst ist. (SAP, Navision etc.) Prüfen die auch die Zeitstempel vor dem speichern oder senden die zusätzliche Informationen an den Server?

Es gibt ja (prinzipiell) nur diese drei Möglichkeiten:

a. Das letzte "Save" gewinnt immer
oder
b. Vor jedem "Save" prüfen, ob es neuere Daten gibt
oder
c. Server mitteilen, welche Daten tatsächlich geändert wurden.

Vielleicht könnten andere auch noch kurz berichten, was bei ihnen der Standard dafür ist.

Danke!

P
1.090 Beiträge seit 2011
vor 8 Jahren

Google mal nach "Concurrency", da findest du einiges zu dem Thema.

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

F
10.010 Beiträge seit 2004
vor 8 Jahren

@carl:
Du solltest mal genau schauen was bei MS Sql ein Timestamp ist, jedenfalls nicht was du da meinst.

Und genau die 3 Möglichkeiten hat man, und es obliegt DIR das richtige zu machen.

3.825 Beiträge seit 2006
vor 8 Jahren

Hallo Carl,

in meiner Anwendung sperre ich einen Datensatz wenn ein Benutzer ihn bearbeitet. Ein zweiter Benutzer, der den gleichen Datensatz bearbeiten möchte, bekommt die Meldung "Datensatz ist in Bearbeitung von Benutzer XY".

Das nennt man "Pessimistic Locking" oder "Pessimistic Row-Locking".

Welches die beste Art ist gleichzeitige Änderungen zu verarbeiten ist sehr umstritten, da gibt es lange Diskussionen drüber, auch in diesem Forum.

Bei deiner Lösung würde meine Anwender nach einer Änderung immer "Ja" drücken bei der Frage "Möchten Sie fortfahren und speichern ?". Somit wären Änderungen eines anderen Benutzers überschrieben.

Schau auch hier : http://www.codeproject.com/Articles/114262/ways-of-doing-locking-in-NET-Pessimistic-and-opt

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

C
carl Themenstarter:in
22 Beiträge seit 2011
vor 8 Jahren

in meiner Anwendung sperre ich einen Datensatz wenn ein Benutzer ihn bearbeitet.

Guter zusätzlicher Hinweis.

In dem beschriebenen Fall ist es aber ja so, das der erste Anwender seine Bearbeitungen schon abgeschlossen hat. Er hat schon gespeichert.

Der zweite Benutzer kennt die neuen Daten nicht, weil er die Eingabemaske nicht aktualisiert hat.

Die beste Lösung wäre wohl also:

1.) Der Benutzer beginnt ein Objekt zu bearbeiten.

2.) Prüfung, ob gesperrt. => Abbruch mit Meldung "Zur Zeit nicht möglich"

3.) Wenn nicht gesperrt, dann Prüfung, ob Aktualisierung notwendig. => Aktualisieren.

4.) Datensatz sofort nach Aktualisierung sperren.

5.) Bearbeitung beginnt.

6.) Speichern oder Änderungen rückgängig.

7.) Entsperren.

8.) Datensatz ist wieder bereit

By the way: Die Anwendung arbeitet nicht mit direkten Datenbankconnections, sondern jede Aktion wird per SOAP und TCP gegen ein Webservice-Proxy programmiert. Ein direktes sperren der Row im SQL-Server fällt daher flach. Jede Statusabfrage, Sperren usw. muss bei mir also manuell gesetzt werden.

16.835 Beiträge seit 2008
vor 8 Jahren

Schau Dir die beiden Themen Optimistic locking und Pessimistic locking an. Nicht nur jetzt irgendwie was in 5 Minuten ausdenken. =)
Das beste gibt es nicht. Sogar innerhalb einer Anwendung ist mal Variante OL besser und mal PL.

C
carl Themenstarter:in
22 Beiträge seit 2011
vor 8 Jahren

Auf jeden Fall. Lösungen sind immer individuell.

Für meinen Fall finde ich "Pessimistic Exclusive locking" am besten. Da kann zwar immer noch einiges schief gehen, wenn im Zeitablauf 2 User zufällig gleichzeitig sperren etc, aber man hat dann zumindest alles getan, um den Fall zu verhindern.

Das von mir weiter oben beschriebene Prozedere gefällt mir schon ganz gut und so werde ich weiter vorgehen. (Sperren, Aktualisieren, Bearbeiten, Speichern, Entsperren)

Vielen Dank für die vielen Hinweise.

3.825 Beiträge seit 2006
vor 8 Jahren

Da kann zwar immer noch einiges schief gehen, wenn im Zeitablauf 2 User zufällig gleichzeitig sperren

Nein, kann es nicht. Der zweite bekommt die Meldung "Datensatz gesperrt".

Wenn das Sperren aus mehreren Aktionen besteht dann diese in eine Transaktion packen.

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

16.835 Beiträge seit 2008
vor 8 Jahren

Denk auch an einen Mechanismus einen gesperrten Datensatz zu entsperren.
zB weil ein Mitarbeiter einfach nach Hause geht, die Anwendung abstürzt oder whatever. Manche machen das auch aus einer Kombination von beiden Lösungen, sodass ein Eintrag nach X Minuten entsperrt wird.

T
708 Beiträge seit 2008
vor 8 Jahren

By the way: Die Anwendung arbeitet nicht mit direkten Datenbankconnections, sondern jede Aktion wird per SOAP und TCP gegen ein Webservice-Proxy programmiert. Ein direktes sperren der Row im SQL-Server fällt daher flach. Jede Statusabfrage, Sperren usw. muss bei mir also manuell gesetzt werden.

Es wäre imho Aufgabe eben dieses Proxy´s bzw. der Datenbankanwendung dahinter, dieses Verhalten zu melden.
Benutzer A & B laden einen Datensatz inklusive Timestamp. Benutzer A modifiziert ihn, der Datensatz wird an den Webservice übermittelt. Dieser hält den Timestamp der Datenbank gegen den übermittelten. Ist der identisch, wird der DS modifiziert.

Nun kommt Benutzer B: Datensatz ändern & übertragen. Timestamp stimmt nicht mehr mit dem aus der Datenbank überein. Es wird eine Exception aufgerufen und an den Benutzer übermittelt. (Der DS wurde zwischenzeitlich modifiziert, laden Sie ihn bitte neu...)

Nun muss B den Datensatz neu laden und seine Änderung erneut ausführen. (Oder eben nicht, weil A das selbe geändert hat, oder eine Sperre gesetzt wurde, usw.).

Den Datensatz selbst zu sperren, wie Bernd es beschreibt, ist bei dieser Herangehensweise noch eine Hierarchie höher anzusiedeln.
Bevor ein Datensatz wirklich geschrieben wird, also nachdem Vergleich des Timestamps, wird dieser gesperrt. Selbst wenn A & B in der selben Sekunde eine Änderung abschicken und der Timestamp sich noch nicht geändert hat, wir es keine Inkonsistenz geben. Einer bekommt die Meldung (Sie sind Opfer einer Sperre geworden)
Solch ein Verhalten ist gerade bei längeren Transaktionen und der Änderung an vielen Tabellen gleichzeitig, absolut notwendig.
Einer bucht den Wareneingang, der Andere den Ausgang. Das kann schonmal 1-2 Sekunden dauern. Sobald beide den Lagerbestand modifizieren wollen, bekommt einer einen Fehler gemeldet.

Daher ist genau dieses Vorgehen gängige Praxis. Auch bei SAP und Dynamics NAV.

3.825 Beiträge seit 2006
vor 8 Jahren

trib : Bei Waren-Eingang und -Ausgang habe ich keine Sperren, nur Transaktionen.

Wenn ein Eingang und ein Ausgang exakt gleichzeitig gebucht wird dann muss der, der als zweiter dran kommt eben 2 Sekunden länger warten, da die Transaktionen nacheinander ausgeführt werden.

Die Sperre tritt nur dann in Kraft wenn jemand den Datensatz auf dem Bildschirm ändert und gerade neue Werte in die Maske eingibt.

Der zweite Anwender muss den Datensatz nicht erneut laden, die inzwischen gemacht Änderungen werden automatisch geladen.

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

C
carl Themenstarter:in
22 Beiträge seit 2011
vor 8 Jahren

Es wäre imho Aufgabe eben dieses Proxy´s bzw. der Datenbankanwendung dahinter, dieses Verhalten zu melden.

Ja, das ist richtig, allerdings werde ich das dennoch manuell über ein zwei separate Datenbankfelder pro Datensatz lösen. Der Hintergrund dafür ist, das die Anwendung nicht auf einen bestimmten Datenbank-Provider (SQL Server, Oracle, MySQL...) setzt, sondern so flexibel sein soll, das man die Datenbanken austauschen kann. Ein "natives" Locking kommt daher nicht in Frage. Der komplette Datenbankkontext wird gekapselt.

Denk auch an einen Mechanismus einen gesperrten Datensatz zu entsperren.

Auf jeden Fall..... 👍.

Der zweite Anwender muss den Datensatz nicht erneut laden, die inzwischen gemacht Änderungen werden automatisch geladen.

Genau. Per Default sind alle Eingabefelder lesbar, aber gesperrt. Sobald der User "Editieren" auswählt, wird die Sperre geprüft und wenn nicht vorhanden gesetzt und sofort aktualisiert. So ist sichergestellt, das man immer mit den aktuellsten Daten arbeitet.

5.299 Beiträge seit 2008
vor 8 Jahren

Du siehst, es ist sehr schwierig.
Dabei ist das Locken von Datensätzen vlt. noch das einfachste, aber die Anwendung muss auch damit umgehen können, dass Datensätze u.U. auch gesperrt sind, bzw. zwischenzeitlich ihren Sperr-Zustand ändern.
Und auch der BenutzerKomfort leidet darunter, weil bei lockablen Daten muss man immer einen Extra-Edit-Modus betreten und verlassen, und in diesem Edit-Modus ist auch immer nur ein einzelner Datensatz zugreifbar (oder zumindest nur ganz wenige).
Und natürlich grundsätzlich unerfreulich für den User, wenn er Bescheid kriegt, dasser den gewünschten DS grad nicht bearbeiten kann.

Nach der einfachsten Lösung sollte man daher auch immer Ausschau halten, nämlich ob man iwie hinkriegt, dem User nur Daten zu präsentieren, die im Lockstate unveränderlich sind.
Also entweder grundsätzlich gelockt, wo er eh kein Speicher-Recht hat, oder "seine eigenen" Daten, mit denen er machen darf was wolle.

Der frühe Apfel fängt den Wurm.