Ok, jeder weiß, dass von einer globalen Sitzung pro Anwendung mit (N) Hibernate abgeraten wird. ABER ich habe einen sehr spezifischen, scheinbar nicht standardisierten Anwendungsfall, für den es die ideale Lösung zu sein scheint.
Um es zusammenzufassen: Meine (Server-) Anwendung hat grundsätzlich alle ihre persistenten Daten ständig im Speicher und fragt niemals die Datenbank für den normalen Betrieb ab. Der einzige Grund für eine Datenbank besteht darin, dass die Daten die Lebensdauer des Prozesses überstehen. Ich möchte nur die Datenbank beim Anwendungsstart abfragen, um alles in den Speicher zu holen. Die Datenbank ist nur etwa 5-10 MB realistisch.
Wenn ich jetzt dem Rat folge, dass Sitzungen kurzlebig sein müssen, muss ich alle meine Daten für jede Geschäftstransaktion zusammenführen oder irgendwie manuell alle Änderungen verfolgen, anstatt die automatische Änderungsverfolgung von NHibernate zu nutzen. Dies macht die Implementierung von Persistence sehr schwierig, ohne dass ein hoher Leistungsaufwand entsteht.
Meine Frage ist also, ob es Gründe gibt, warum ich keine globale Sitzung für diesen speziellen Anwendungsfall verwenden sollte?
Gemeinsame Argumente gegen globale Sitzungen, die ich kenne:
Der Cache der ersten Ebene wird im Laufe der Zeit mit der gesamten Datenbank gefüllt = & gt; Das macht mir nichts aus, da ich eigentlich alle Daten im Speicher haben möchte!
Veraltete Daten und Nebenläufigkeitsprobleme = & gt; Meine Anwendung ist so konzipiert, dass der gesamte Code, der auf persistente Daten zugreifen oder diese ändern kann, ein Singlethread-Prozess sein muss (eine bewusste Design-Entscheidung), und es ist die einzige Anwendung, die in die Datenbank schreiben kann. Das sollte also kein Problem sein.
Sitzung wird beschädigt, wenn sie eine Ausnahme auslöst (z. B. DB-Timeout) = & gt; Das ist das einzige wirkliche Problem, das ich sehen kann, aber kann gelöst werden, indem man die Sitzung verwirft, eine neue erstellt und alle Daten auffrischt. Teuer, aber Ausnahmen sollten sehr selten sein und können nur entweder durch einen großen Fehler oder große Infrastrukturprobleme verursacht werden, die beide so schnell wie möglich gelöst werden sollten.
Ich glaube also, dass es keinen Grund gibt, warum ich keine globale Sitzung für meinen speziellen Anwendungsfall verwenden sollte . Oder gibt es etwas wichtiges, das mir fehlt?
Update 1: Es ist eine Serveranwendung
Update 2: Dies bedeutet keine langlebigen globalen Transaktionen. Transaktionen würden immer noch kurzlebig sein - eine langlebige Sitzung, viele kurzlebige Transaktionen.
Wenn Sie alle Transaktionen, die von mehreren Threads stammen, zu einem einzigen dedizierten Back-End-Thread-Executor fächern , können Sie tatsächlich eine einzelne Sitzung pro Anwendung verwenden.
Ausnahmen können durch Sperrzeitüberschreitungen, Serverabstürze oder Einschränkungsverletzungen ausgelöst werden, so dass das Zurücksetzen der Sicherungssitzung zum Verwerfen aller Cache-Einträge der ersten Ebene führt, was für Ihren Anwendungsfall schlecht ist. In diesem Fall müssen Sie alles aus der DB abrufen und da Sie einen einzelnen Back-End-Thread verwenden, werden alle anderen Client-Threads blockiert, was nicht überzeugend ist.
Ich würde Ihnen raten, stattdessen den Second-Level-Cache zu verwenden . Sie können den 2LC-Provider so konfigurieren, dass er im Arbeitsspeicher streamt, statt auf die Festplatte zu überlaufen. Sie können alle Daten im Cache der zweiten Ebene laden, wenn die Anwendung gestartet wird, und eine NONSTRICT_READ_WRITE Cache Concurrency-Strategie verwenden um die Schreibvorgänge zu beschleunigen (Probleme mit der Parallelität sind für Sie sowieso kein Problem).
Sie müssen sicherstellen, dass Sie auch 2NL-Caching für Sammlungen verwenden .
>Der einfachste Entwurf besteht darin, eine Session-pro-Anfrage zu verwenden, da die Session sowieso irgendwie leicht ist und sowieso Daten aus dem In-Memory-2LC holt.
Sie müssen einige Leistungstests durchführen, um festzustellen, ob es sich lohnt, eine Sitzung erneut zu verwenden, anstatt bei jeder einzelnen Transaktion eine neue Sitzung zu erstellen. Sie könnten herausfinden, dass dieser Prozess sowieso nicht Ihr Engpass ist und Sie sollten keine Optimierung ohne einen echten Beweis machen.
Ein weiterer Grund für das Verwerfen der Sitzung besteht darin, dass die meisten datenbankbezogenen Ausnahmen nicht wiederherstellbar sind. Wenn der Server ausfällt oder die aktuelle Anfrage eine Constraint-Verletzung auslöst, wird durch das erneute Einlesen sowieso nichts repariert.
Einer der möglichen Nachteile, die ich sehen kann, ist, dass die dreckige Prüfung sehr lange dauern kann. Sie müssen den Bytecode-Instrumentierungsmodus verwenden, um dieses Problem zu lösen.
Außerdem kann der serialisierte Zugriff auf den Server die Leistung wesentlich mehr beeinträchtigen als das erneute Erstellen der Objekte aus dem Cache der zweiten Ebene (die Erstellung von Objekten ist in modernen JVMs sehr schnell). Dies trifft sogar auf Einzelbenutzeranwendungen zu (der Benutzer kann auf einem Bildschirm eine lang andauernde Operation auslösen und auf der anderen Seite etwas anderes tun, oder der Server kann eine geplante Operation auslösen, wodurch der Benutzer bis zum nächsten Zugriff auf den Server blockiert wird Operation ist getan).
Drittens kann die Neugestaltung Ihres Ansatzes später schwierig sein, wenn die Notwendigkeit besteht, gleichzeitig Anfragen auszuführen.
Als nächstes werden Sie nicht vermeiden, bei der Ausführung von Abfragen trotzdem zur Datenbank zu gehen.
Schließlich ist die erweiterte Sitzung eine Hibernate-Funktion, die nicht so häufig verwendet wird wie das klassische Session-pro-Request-Muster. Obwohl Hibernate ein gutes Stück Software ist, ist es auch komplex und hat daher viele Fehler. Ich würde mehr Bugs und schwächere Community-Unterstützung / Dokumentation in Bezug auf weniger genutzte Features erwarten (wie in jedem anderen Framework).
Mein Vorschlag ist also, den Second-Level-Cache zu verwenden und die Parallelitätsprobleme mit optimistischen / pessimistischen Sperren zu behandeln, abhängig von den Anwendungsfällen. Sie können das Zwischenspeichern aller Entitäten standardmäßig aktivieren, indem Sie den gemeinsam genutzten Cache-Modus DISABLE_SELECTIVE
oder ALL
verwenden, wie in Dokumente .
Die Gründe dafür, keine globale Sitzung zu verwenden, können wie folgt zusammengefasst werden:
* Cache der ersten Ebene: Das musst du verstehen. Der Cache der ersten Ebene ist nicht nur Speicher. Eine Folge des Caches der ersten Ebene ist, wenn ein Objekt gespeichert oder gelöscht oder abgefragt wird. (N) Der Ruhezustand muss sicherstellen, dass sich die Datenbank vor diesem Ereignis in einem konsistenten Zustand mit Ihrem Speicher befinden muss. Das ist Spülen. Allerdings verfügt (n) Hibernate über eine einzigartige Funktion, die als Transparente Persistenz bezeichnet wird. Im Gegensatz zu anderen ORMs wie Entity Framework, haben Sie keine Spur, was schmutzig ist. NHiberante macht das für Sie. Aber die Art, wie es funktioniert, ist etwas teuer. Es vergleicht alle vorherigen Objektzustände mit den neuen und versucht zu erkennen, was sich geändert hat. Wenn also der Cache Ihres ersten Levels voller Entitäten ist, verschlechtert sich die Leistung. Dieses Problem kann auf zwei Arten umgangen werden:
1-) mit session.Flush (); session.Clear ();
2-) statusfreie Sitzung verwenden.
Im ersten Fall gehen alle ausstehenden Änderungen in die Datenbank. Danach können Sie die Sitzung sicher löschen. Behält jedoch die Daten im Speicher, auch wenn Sie die Sitzung löschen, bis die Transaktion erledigt ist. Dies liegt an der Möglichkeit, dass Sie die Transaktion abstimmen können, um am Ende abgelehnt zu werden. (Kann auf Anfrage mehr Informationen dazu geben)
Zweiter Fall, bei zustandsloser Sitzung verhält sich (n) Hibernate wie ein Mikro-ORM. Es gibt kein Tracking. Es ist leicht, aber gibt Ihnen mehr Verantwortung.
* Sitzungsbezogene Ausnahmen: Ein weiterer wichtiger Grund für die Nichtverwendung einer sitzungsweiten Sitzung besteht darin, dass immer dann, wenn eine Ausnahmebedingung in Bezug auf Sitzung oder Datenbank auftritt (z. B. Verletzung der eindeutigen Einschränkung), Ihre Sitzung zum Scheitern verurteilt ist. Sie können nicht mehr damit arbeiten, da sie sich in einem inkonsistenten Zustand mit der Datenbank befindet. Daher muss Ihre globale Sitzung erneuert werden, was zu mehr Komplikationen führt.
* Threadsicherheit: Weder die Sitzung noch ein ADO.NET-Konstrukt ist Thread-sicher. Wenn Sie ein globales Sitzungsobjekt zusammen mit mehreren Threads verwenden, müssen Sie eine Art Threadsicherheit sicherstellen. Das kann sehr sehr schwierig sein.
Tags und Links java hibernate orm transactions nhibernate