2012-05-19 6 views
11

Ich benutze Hibernate mit Spring on Tomcat. Ich lese und lese das oft auf JBoss wiki page auf das Thema, und das war hilfreich. Aber es hinterlässt mir einige Fragen.Hibernate offene Sitzung in der Ansicht: Transaktion pro Anfrage?

  1. Die Idee, eine Transaktion für jede Anfrage zu starten, beunruhigt mich. Ich denke, ich könnte den Filter auf bestimmte Controller beschränken - vielleicht setzen alle meine Controller, die eine Transaktion benötigen, unter einen Pseudo- "tx" -Pfad oder so. Aber ist es nicht eine schlechte Idee, Transaktionen zu verwenden, wenn Sie nicht wissen, ob Sie eine brauchen werden? Und wenn ich nur ein paar Anfragen einlese - gelesen, die sehr wahrscheinlich aus einem Cache stammen - bin ich nicht besser ohne eine Transaktion?

  2. Ich habe Beiträge gelesen, in denen erwähnt wird, wie sie die Transaktionen auf der Service-Ebene behandelt haben, und ich möchte dies mit Spring machen. Aber wie sieht der Filtercode aus? Ich möchte immer noch die Sitzung in meiner Sicht für einige faul laden.

  3. Wenn ich nur sessionFactory.getCurrentSession() in meinem Filter aufrufen muss, wie wird es wieder in die Session-Factory für die Wiederverwendung "freigegeben"? (Ich erwartete eine session.close() oder etwas, auch wenn Transaktionen verwendet werden.) Wer sagt der Sitzungsfabrik, dass diese Sitzung wiederverwendet werden kann?

  4. Vielleicht ist es der beginTransaction() Aufruf, der eine bestimmte Datenbankverbindung für die Dauer einer Anfrage an eine bestimmte Sitzung bindet? Andernfalls zieht eine Sitzung Datenbankverbindungen aus dem Pool nach Bedarf, oder?

Vielen Dank für Ihre Geduld mit all meinen Fragen.

(Und wenn deine Antwort ein Link zur Frühlingsdokumentation sein wird, bringst du mich zum Weinen. Das willst du nicht, oder? Ich werde echtes Geld bezahlen, wenn die Leute aufhören würden, auf Spring zu antworten Fragen auf diese Weise.)

Antwort

20

Ihre Bedenken sind gültig, die auf der Wiki-Seite zur Verfügung gestellte Lösung ist zu einfach. Die Transaktion sollte nicht auf der Web-Schicht verwaltet werden - sie sollte auf der Service-Schicht behandelt werden.

Die richtige Implementierung würde eine Sitzung öffnen und sie an einen Thread im Filter binden. Keine Transaktion wird gestartet. Die Sitzung wird in den Modus "Nur-Lesen-Modus" versetzt. Ein Service-Aufruf würde die Sitzung in den Flush-Modus Auto & Start/Commit der Transaktion setzen. Sobald die Service-Methode beendet ist, wird der Session-Flush-Modus auf nie zurückgesetzt.

Es gibt auch eine Option, die Sitzung im Filter nicht zu öffnen. Jeder Dienstschichtaufruf würde eine separate Sitzung &-Transaktion öffnen - nachdem der Dienstanruf beendet ist, wird die Sitzung nicht geschlossen, sondern für den verzögerten Abschluss registriert. Die Sitzung wird geschlossen, nachdem die Webanforderungsverarbeitung abgeschlossen ist.

Feder bietet OpensessionInViewFilter, die wie oben beschrieben funktioniert. Also ignoriere den jboss Wiki Artikel und konfiguriere einfach den OpenSessionInViewFilter - alles wird gut.

SessionFactory.getCurrentSession() - erstellt intern und weist die Sitzung einem lokalen Thread zu. Jede Anfrage/jeder Thread hat eine eigene Sitzung. Sobald die Verarbeitung der Webanforderung abgeschlossen ist, wird die Sitzung geschlossen. In Ihrem Code müssen Sie nur SessionFactory.getCurrentSession() verwenden und müssen es nicht schließen. Das Codebeispiel auf der jboss-Wiki-Seite ist falsch - es sollte eine SessionFactory.getCurrentSession(). Close() im finally-Block enthalten.Oder sie verwenden möglicherweise die JTA-Transaktion und den konfigurierten Ruhezustand zum Öffnen/Schließen der Sitzung in Verbindung mit der JTA-Transaktion.

+0

Ich ging von hier nach dort und dann nach dort, über das Web für eine Woche zu diesem Thema überspringen ... und das ist das erste Mal, dass ich gelesen habe, dass Spring einen OpenSessionInView-Filter hat. Vielen Dank. – Marvo

+0

Mann, das funktioniert einfach wunderbar. Vielen Dank! – Marvo

+0

Ich dachte immer, es würde als eine Transaktion funktionieren. Aber die Transaktion ist wirklich begrenzt durch @Transactional. Danke für die Erklärung. –

0

Es ist kein Problem, wenn der Filter eine Sitzung für jede Anfrage erstellt, da die Sitzungen aus einem Sitzungspool stammen und wiederverwendet werden. Aus der Sicht des Betriebssystems passiert nichts.

Eine Hibernate-Sitzung ist eine Tcp- (oder Socket-/Pipe-) Verbindung zum Datenbankserver. Die Kosten für die Erstellung der db-Conn hängen stark vom sql-Typ ab (postgresql ist besonders schlecht, obwohl es in jedem Fall sehr gut ist). Aber es bedeutet wirklich nichts, weil Hibernate die Datenbankverbindungen wiederverwendet.

Die einfache Hibernate-Filterlösung startet für jede Anforderung eine neue Transaktion in der Sitzung. Es ist eine Transaktion aus der Sicht des SQL: Es ist eine "BEGIN" und "COMMIT" -Abfrage. Es ist immer teuer, und das sollte reduziert werden.

IMHO eine mögliche Lösung waren, wenn die Transaktionen nur bei der ersten Abfrage der aktuellen Anfrage gestartet wurden. Vielleicht hat der Frühling etwas Brauchbares dafür.

+1

Wir haben den OpenSessionInView Filter (siehe oben) in Kombination mit der Spring @Transactional Annotation verwendet. Bis jetzt funktioniert es großartig. – Marvo

+0

@Marvo Ich hatte keine so gute Erfahrung damit. Sie haben keine Kontrolle, was genau passiert und warum. In meinem letzten Projekt hatte ich mehrere Datenbankverbindungen (einige Einheiten verbinden die erste, einige mit der zweiten) mit quergerichteten Federschichten, und einige der Prozesse wurden von Quartz initiiert, einige aus dem Netz. Die Situation war komplex und das Hauptproblem bestand darin, dass Sie in einer Annotations- oder/und AOP-basierten Sache sehr genau kontrollieren können, was fehlgeschlagen ist oder wo das Problem liegt. Es funktioniert einfach oder nicht, aber Sie können nicht in ihnen sehen. In einer klaren prozeduralen Umgebung ist es trivial. – peterh