2009-08-11 12 views
1

Ich bin kein Anfänger im Winterschlaf, aber ich bin ein Anfänger in der Arbeit mit Hibernate im Frühjahr. Ich lese das Buch Frühling in Aktion. Also habe ich eine kleine Anwendung geschrieben, um die Beispiele im Buch zu verstehen. Hier eine Extraktion meiner Bewerbung. Ich kann dir mehr geben, wenn du willst.Session-Behandlung in Hibernate mit Spring

@Transactional(propagation = Propagation.SUPPORTS, readOnly = true) 
public void runQuery() 
{ 
    final BuildingDAO buildingDAO = (BuildingDAO) applContext.getBean("buildingDAO"); 
    final Building building = buildingDAO.getBuildingById("HQ"); 
    logger.debug("Loaded building: " + building.getId()); 
    logger.debug("Loaded building: " + building.getName()); 
} 

Das Objekt wird ohne Probleme geladen. Das Protokoll des Primärschlüssels ist ebenfalls kein Problem. Das Protokoll des Zeichenfolgenattributs verursacht jedoch eine LazyInitializationException. Ich verstehe, warum das passiert. Hibernate hat einen Proxy mit Proxyattributen zurückgegeben. Wenn ich auf ein lazy-loaded-Attribut zugreifen möchte, hat Hibernate versucht, den Wert zu laden, aber die Sitzung wird geschlossen. Lazy Loading ist ein großartiges Feature von Hibernate und ich möchte es nicht verpassen.

Spring verwaltet die Session-Behandlung für mich. Spring öffnet eine Hibernate-Sitzung in der load-Methode der Hibernate-Vorlage und schließt die Sitzung, nachdem die Methode beendet wurde.

Aber jetzt möchte ich Spring darauf hinweisen, dass die Sitzung in der gesamten Methode (runQuery()) geöffnet sein sollte, die oben gezeigt wird. Ich möchte einige Attribute des Objekts anzeigen. Ich erwähnte, dass ich einen Tranaktionsmanager von Spring dazu benutzen kann. Also verwende ich die Transaktionsannotation von Spring. Aber es funktioniert nicht. Vielleicht ist meine Annahme falsch, den Transaktionsmanager zu verwenden.

Hat jemand eine Idee, Spring zu empfehlen, eine Sitzung für die gesamte Methode offen zu halten?

Antwort

3

Sind Sie sicher, Propagation.SUPPORTS ist das, was Sie wirklich brauchen? Das erzwingt nicht das Vorhandensein einer Transaktion, es benutzt es nur, wenn es da ist. Ein anderer Teil des Systems muss die Transaktion starten und festschreiben. Wenn keine vorhanden ist, wird die Sitzung möglicherweise nicht so weit wie Ihre Protokollanweisungen beibehalten, was zu einem verzögerten Ladefehler führt.

Versuchen Sie es mit einer anderen Isolationsstufe (wie REQUIRED, oder noch besser, geben Sie nicht alles an, und verlassen Sie sich auf den Standard) und sehen, ob das Ihr Problem behebt.

2

Wenn Sie auf REQUIRED umschalten oder es einfach leer lassen, wird Ihr Problem behoben. Propagation.SUPPORTS eigentlich nicht eine Transaktion starten ... siehe http://www.ibm.com/developerworks/java/library/j-ts2.html

Sie haben wahrscheinlich nicht gesperrten nicht transaktionale liest (die Standardeinstellung aktiviert ist) und damit die Lese erfolgreich ist, aber die Transaktion für die Lese ist nur für das Lesen selbst (nicht für nachfolgende Lesevorgänge auf dem Objekt zurückgegeben).

Die Kategorie für die Protokollierung der Transaktionsaktivität lautet: org.springframework.transaction IIRC - Wenn Sie dies auf DEBUG setzen, sehen Sie Details darüber, wann Transaktionen gestartet und festgeschrieben werden.

0

Wenn Sie möchten, dass RunQuery innerhalb einer Spring-Transaktion ausgeführt wird, müssen Sie ein Objekt der Klasse abrufen, das es als eine Spring-Bean aus dem Container definiert. Auf diese Weise kann Spring die Transaktionslogik um die Bean wickeln (und welche Methoden es auch definiert).
Wenn Sie diese Klasse als Spring Bean definieren, können Sie auch keinen (BuildingDAO)applContext.getBean("buildingDAO") aufrufen, da spring den dao in Ihre Klasse einbindet (wenn Sie ihn im Kontext-XML oder in den Attributen richtig definieren).