Ich beginne ein neues Projekt, versuche diesmal die Dinge richtig zu machen (also mehr als eine Frage), ich brauche vielleicht Hilfe, ich bin mir nicht sicher, was ich falsch mache:
Ich möchte Spring MVC so viel wie möglich nutzen, wie mache ich Sitzung öffnen / schließen von @Transactional bearbeitet?
Wie erfasse ich die Ausnahmen (d. h. nicht existierender Datensatz oder Datenbank fehlgeschlagen), falls vorhanden. Meine Datenbank akzeptiert keine doppelten Einträge wie diesen:
%Vor%Wie kann ich das fangen?
Und für jede nächste Anfrage bekomme ich diese Ausnahme:
%Vor%Was mache ich falsch? Kann jemand einige Verbesserungen in meinem Projekt vorschlagen?
Komponentensuche
Das Wichtigste zuerst: Sie verwenden @Controller, @Service, @Repository und ein @Autowired, aber Sie tun nichts mit ihnen. Ich empfehle den Klassenpfad-Scan . Entfernen Sie die Beans "testServiceDAO" und "testService" aus Ihrer Spring-Kontextdatei und verwenden Sie stattdessen:
%Vor% Das wird diese Beans anhand ihrer Anmerkungen finden und erstellen, anstatt sie im XML deklarieren zu müssen. Fügen Sie @Autowired dem Feld testServiceDAO
in Ihrem Dienst und dem Feld sessionFactory
in Ihrem DAO hinzu. Entfernen Sie die Setter für diese Felder. Sie werden nicht mehr benötigt. Das component-scan-Tag übernimmt auch die Autowirkung für Sie. Um den Namensraum context
zu verwenden, müssen Sie ihn zu Ihrem Root-Element hinzufügen. Zum Beispiel:
Transaktionsverwaltung
Um @Transactional
Da Ihr Transaktionsmanager-Bean den Namen "transactionManager" hat, wird es automatisch gefunden. Sie müssen auch den "tx" -Namespace zu Ihrem Root-Element hinzufügen, so dass es etwa wie folgt aussehen sollte:
%Vor% Damit dies funktionieren kann, müssen Sie sowohl session.beginTransaction()
als auch session.close()
von Ihrer DAO-Methode entfernen. Wenn Sie Ihre eigene Transaktion auf diese Weise öffnen, mischen Sie programmatische und deklarative Transaktionsabgrenzungen, und der deklarative Weg ist normalerweise besser. Außerdem sollten Sie niemals jemals eine Sitzung in einem DAO in einem realen Projekt schließen. Das wird dich in alle möglichen Schwierigkeiten bringen.
Ausnahmebehandlung
Ihre MySQLIntegrityConstraintViolationException
, die eine datenbankspezifische Ausnahme darstellt, würde von Hibernate abgefangen und in ein ConstraintViolationException , was aus Ihrem DAO kommen würde; Da Ihr DAO jedoch jetzt ein @ Repository ist, können Sie von Spring's Ausnahmeübersetzung . Damit wird die Hibernate-Ausnahme von Spring abgefangen und in eine DataIntegrityViolationException . Die Behandlung von Datenbankausnahmen macht immer Spaß!
Sitzungsverwaltung
Verwenden Sie ein OpenSessionInViewFilter oder OpenSessionInViewInterceptor ? Wenn dies der Fall ist, wird eine Hibernate-Sitzung geöffnet, wenn eine Anforderung zuerst empfangen und nach dem Schreiben der Antwort geschlossen wird. Wenn nicht, wird die Sitzung erst gestartet, wenn eine Transaktion beginnt (bei einer @ Transactional-Methode), und sie wird geschlossen, wenn diese Transaktion abgeschlossen ist. Mit dem Filter / Interceptor können Sie Dinge in der Ebene "Ansicht" ausführen, die einen Aufruf an die Datenbank erfordern, insbesondere wenn Sie über träge Beziehungen oder Lazy-Loaded-Objekte verfügen, die Sie zum Rendern der Ansicht benötigen. Wenn die Sitzung nicht verfügbar ist - wie es nicht der Fall ist, wenn sie nur für die Länge der transaktionalen Service-Methode existiert - können Sie diese Dinge nicht in der Ansicht ausführen und Sie erhalten den berüchtigten LazyInitializationException .
Was den Fehler "Spülung der Sitzung nach einer Ausnahme tritt nicht" betrifft, den Sie bekommen, sehe ich nichts unmittelbar, was mich denken lässt, dass das passieren sollte. Vielleicht ist etwas in Ihrem Web-Tier-Spring-Kontext falsch konfiguriert, oder vielleicht gibt es ein seltsames Zusammenspiel in der Art und Weise, wie Sie die Transaktion und Sitzung direkt im DAO abwickeln.
Wie führe ich das Öffnen / Schließen von Sitzungen durch
@Transactional
?
Sie benötigen <tx:annotation-driven />
(und den tx
Namespace) in Ihrem Frühlingskontext.
(siehe Verwenden von @Transactional
)
Ich würde stark empfehlen, weit entfernt von der @Transactional im Frühjahr zu bleiben. Bleiben Sie für Ihre Verwendung bei einem open-session-in-view -Muster. Wenn eine Anfrage eingeht, wird eine Sitzung geöffnet und eine Transaktion gestartet. Wenn eine Ausnahme oder ein anderer Fehler auftritt, führen Sie einen Rollback der Transaktion aus. Sonst begehen. Auf diese Weise kümmert sich Hibernate um das schwere Heben für Sie.
Wenn Sie den Pfad von @Transactional durchlaufen, gelangen Sie in ein trübes Reich von Lazy-Loading-Ausnahmen und anderem seltsamen Verhalten, während Sie versuchen, herauszufinden, was von wo kam. Im schlimmsten Fall müssen Sie die Reihenfolge, in der Methoden aufgerufen werden, sorgfältig überwachen (d. H. Achten Sie genau auf Ihren Stack), um sicherzustellen, dass Sie über die richtigen Berechtigungen verfügen.
Am schlimmsten ist, dass Sie, wenn Sie @Transactional auf Dinge setzen, die sich bereits im Cache der ersten oder zweiten Ebene befinden, viele BEGIN / END-Transaktionen in Ihre Datenbank bekommen, ohne dass tatsächliche Abfragen ausgeführt werden ( weil sie im Cache sind). Dies kann Ihre Leistung zerstören und ist fast unmöglich zu unterdrücken.
Nachdem die Transaktion in Ihrer Sitzung explodiert ist, müssen Sie einen Rollback durchführen. Je nachdem, um welche Semantik es sich handelt, müssen Sie möglicherweise Ihre Sitzung wiederholen. Die Fehlerbehebung für die erste ist einfach - machen Sie zuerst einen Check, um zu sehen, ob die Entität bereits vor dem Speichern existiert. Das wird die zweite beheben.
Sehen Sie sich diesen Artikel an, der Hibernate / JPA und myBatis für weitere Kommentare vergleicht .
Tags und Links java hibernate spring spring-mvc