Ich arbeite an einer großen Anwendung, die komplexe "Ereignisse" mit einer großen Menge an Daten verwaltet.
Die Anwendung besteht aus einem Client (hauptsächlich C#, .NET 2.0), einem WCF-basierten Server, der auf IIS läuft (Webdienste auf dieser Ebene), und einem Daten-Backend, das auf NHibernate mit einem MS SQL Server-Datenbank-Backend basiert.
Bei folgendem Szenario ist ein Fehler aufgetreten:
Mehrere Benutzer (in diesem Fall 6, in unserem Test) speichern gleichzeitig ein persistiertes Objekt (z. B. ein Ereignis) auf dem Client. (Dies geschieht über einen verbalen Countdown, so dass es aufgrund der Reaktionszeiten zu einem Unterschied von etwa einer Sekunde kommt.)
Wenn sie Objekte auf dem Client speichern, ruft der Client den Server auf, um das Objekt zu speichern. Der Server führt die erforderliche Geschäftslogik aus und überträgt die Änderung dann über NHibernate.
In dieser Situation (mehrfaches Speichern über Serviceaufrufe) werden einige Kunden mit einer unbearbeiteten Ausnahme zurückkommen:
"Zeile wurde durch eine andere Transaktion aktualisiert oder gelöscht"
Dies ist eine NHibernate-Ausnahme.
Bei meinen Nachforschungen habe ich einige Fälle dieses Fehlers gefunden, aber es war immer sequenziell. Unsere Anwendung ist sequenziell in Ordnung, dies geschieht nur bei gleichzeitigen Speichern.
Wie sollten mehrere gleichzeitige NHibernate-Transaktionen voreinander geschützt werden?
(Da es sich um eine Anwendung mit hohem Datenaufkommen handelt, ist es gut, wenn die Sperrung auf ein Minimum reduziert wird. Wir können es uns nicht leisten, alle Speicherungen generell zu sperren).
Gibt es NHibernate-Einstellungen, mit denen dies möglich ist? Müssen wir vorher einige Sperren auf der Seite des Servercodes herausfinden? Kann die Datenbank damit umgehen, vielleicht mit unterschiedlichen Einstellungen für den Transaktionsschutz?
Wie bei den meisten Threading-Problemen ist es schwierig, dies zu testen, daher der Ansatz Forschung/Theorie. Wie sind die Erfahrungen mit einer solchen Architektur?
Edit: Weitere Informationen und eine Theorie.
Es scheint, dass das Ändern von Werten, die sich direkt in der Tabelle als Hauptentität befinden, dieses Problem nicht verursacht, während das Ändern von Elementen, auf die über eine Verknüpfung zugegriffen wird, dies tut. (In diesem Fall eine Reihe von Attributen).
Unsere Arbeitstheorie, die auf diese Situation zu passen scheint, ist die folgende:
Für ein und dasselbe Ereignis werden mehrere Daten gespeichert. Jedes Ereignis erhält eine Kopie des bestehenden Ereignisses (zum Ändern). Die ersten Speicherungen sind in Ordnung. Die späteren haben jedoch Aktualisierungen wie das Hinzufügen oder Löschen von Attributen (die eine Join-Tabelle sind) und entdecken, dass das Hinzufügen oder Löschen, das getan werden muss, bereits getan wurde, und brechen ab, weil eine andere Transaktion das Ereignis bearbeitet hat.
Wie sollten wir diese Ereignisse synchron halten?