Frage

Wir verwenden Hibernate (mit JPA) und Hibernate Envers, um den Verlauf von Objekten beizubehalten.Die Webanwendung führt viele Threads aus, einige davon werden durch den RMI-Methodenaufruf von anderen Anwendungen erstellt, einige werden von der Anwendung selbst erstellt und einige werden für die Verarbeitung von HTTP-Anfragen erstellt (sie generieren Ansichten).

Wir verwenden auch das Muster „Open Session In View“ zum Verwalten von Sitzungen, daher enthält unsere web.xml Folgendes:

<filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Der Zugriff auf die Datenbank erfolgt über DAOs, alle verfügen über von Spring eingefügte EntityManager.

@PersistenceContext
protected EntityManager em;

@PersistenceUnit
protected EntityManagerFactory emf;

Alles hat ganz gut funktioniert, bevor wir uns für Hibernate Envers entschieden haben.Wenn ein Thread, der kein Thread zur Ansichtsgenerierung ist, den Code ausführt, um eine alte Version eines Objekts abzurufen, wird die Ausnahme ausgelöst.

@Override
public O loadByRevision(Long revision, Long id) {
    @SuppressWarnings("unchecked")
    O object = (O) AuditReaderFactory.get(em).createQuery().forEntitiesAtRevision(getBaseClass(), revision.intValue())
            .add(AuditEntity.id().eq(id)).getSingleResult();
    return object;
}

Ausnahme im Thread „Scheduler“ org.hibernate.SessionException:Sitzung ist geschlossen!bei org.hibernate.internal.abstractSessionImpl.Errorifclosed (AbstractSessionImpl.java:129) bei org.hibernate.internal.SessionImpl.Createquery (sessionImpl.java:1776) unter org.hibernat.en.enverybuwers.envery. .Java: 226) bei org.hibernate.envers.query.impl.abstractauditQuery.buildquery (AbstractauditQuery.java:92) bei org.hiberNate.envers.Query.impl.Entitiesatrevisions.List (Entitiesatrevision.java:108) at org. hibernate.envers.query.impl.abstractauditQuery.getSingleresult (AbstractAuditQuery.java:110) (...)

Wenn der obige Code vom Thread zum Generieren der Ansicht ausgeführt wird, funktioniert er einwandfrei.Außerdem funktioniert der Nicht-Envers-Code in DAO für jeden Thread einwandfrei.Zum Beispiel der folgende Ausschnitt

@Override
public O load(Long id) {
    final O find = em.find(getBaseClass(), id);
    return find;
}

kann problemlos von RMI-Threads ausgeführt werden.

Warum können Nicht-View-Threads ausnahmslos Methoden auf dem Entitätsmanager aufrufen, aber nicht die AuditReaderFactory von Envers mit diesem Entitätsmanager verwenden?Ich dachte, dass der Aufruf einer Methode auf dem Entity Manager vielleicht eine temporäre Sitzung erstellt, aber das passiert bei der Verwendung von Envers nicht, stimmt das?

Was ist der beste Weg, dieses Problem zu beheben (damit die AuditReaderFactory von jedem Thread aus verwendet werden kann)?

War es hilfreich?

Lösung

Wir haben nicht herausgefunden, warum in Nicht-UI-Threads Methodenaufrufe ausgeführt werden EntityManagerFactory hat funktioniert, aber Methodenaufrufe sind möglich AuditReaderFactory nicht.Wie auch immer, wir haben einen Weg gefunden, das Problem zu beheben.

Die Lösung bestand darin, Methoden mit zu kommentieren @Transactional.Wenn eine Methode in der Aufrufkette vor dem Aufruf der AuditReaderFactory als markiert wurde @Transactional, da war nein SessionException in Nicht-UI-Threads.

Es stellte sich heraus, dass es so war loadByRevision transaktional war nicht ausreichend.Wenn ein von dieser Methode zurückgegebenes Objekt Lazy-Loaded-Persistent-Beutel enthielt, erfolgt der Zugriff darauf außerhalb von loadByRevision Methodenumfang verursacht LazyInitializationException (es gab keine Sitzung).

Die endgültige Lösung bestand darin, sicherzustellen, dass, wenn ein Thread einige Daten aus der Datenbank laden möchte, der gesamte Ladevorgang (Abrufen eines Objekts und Zugriff auf verzögert geladene Sammlungen) innerhalb einer mit Anmerkungen versehenen Methode erfolgt @Transactional.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top