Question

Nous utilisons mise en veille prolongée (avec JPA) et Hibernate Envers persistent à l'histoire des objets.L'application web s'exécute de nombreux threads, certains d'entre eux sont créés par RMI invocation de méthode à partir d'autres applications, certains d'entre eux sont créés par l'application elle-même et certains d'entre eux sont créés pour traiter les requêtes http (ils génèrent des points de vue).

Nous utilisons également l'Open Session In View modèle pour gérer les sessions, afin que notre web.xml contient:

<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>

La base de données est accessible à l'aide de DAOs, tous ont EntityManagers injecté par le Printemps.

@PersistenceContext
protected EntityManager em;

@PersistenceUnit
protected EntityManagerFactory emf;

Tout fonctionnait très bien avant, nous avons décidé d'utiliser Hibernate Envers.Quand un thread qui n'est pas une vue de générer thread exécute le code pour avoir une ancienne version d'un objet, l'exception est levée.

@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;
}

Exception in thread "Planificateur" org.mise en veille prolongée.SessionException:La fermeture de la Session!au org.mise en veille prolongée.interne.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:129) au org.mise en veille prolongée.interne.SessionImpl.createQuery(SessionImpl.java:1776) au org.mise en veille prolongée.envers.outils.de la requête.QueryBuilder.toQuery(QueryBuilder.java:226) au org.mise en veille prolongée.envers.de la requête.impl.AbstractAuditQuery.buildQuery(AbstractAuditQuery.java:92) au org.mise en veille prolongée.envers.de la requête.impl.EntitiesAtRevisionQuery.liste(EntitiesAtRevisionQuery.java:108) au org.mise en veille prolongée.envers.de la requête.impl.AbstractAuditQuery.getSingleResult(AbstractAuditQuery.java:110) (...)

Lorsque le code ci-dessus est exécuté par la vue de génération de fil, il fonctionne très bien.Aussi, le non-envers code dans DAO fonctionne très bien pour tous les fils.Par exemple, le fragment de code ci-dessous

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

peut être exécuté par RMI fils sans problèmes.

Pourquoi pas une vue de threads d'appeler des méthodes sur le gestionnaire d'entité sans exceptions, mais pas Envers' AuditReaderFactory avec l'entité gestionnaire?J'ai pensé que peut-être l'appel d'une méthode sur le gestionnaire d'entité crée une session temporaire, mais cela ne se produit pas lorsque vous utilisez Envers, est-ce vrai?

Quelle est la meilleure façon de résoudre ce problème (de sorte que le AuditReaderFactory peut être utilisé à partir de chaque thread)?

Était-ce utile?

La solution

Nous n'avons pas trouvé la raison de la non-threads l'interface utilisateur des appels de méthode sur EntityManagerFactory travaillé, mais les appels de méthode sur AuditReaderFactory n'a pas.De toute façon, nous avons trouvé un moyen pour résoudre ce problème.

La solution a été d'annoter des méthodes avec @Transactional.Si n'importe quelle méthode de la chaîne d'appel avant l'appel à la AuditReaderFactory a été marqué comme @Transactional, il n'y avait pas SessionException en non-interface de threads.

Il s'est avéré que faire loadByRevision transactionnelle n'était pas suffisant.Si un objet retourné par la méthode contenue chargement paresseux persistante des sacs, l'accès à l'extérieur de l' loadByRevision la portée de la méthode causé LazyInitializationException (il n'y a pas de session).

La solution finale a été de s'assurer que si un thread veut charger des données à partir de la base de données, tous le chargement (obtention d'un objet et d'accéder à chargement paresseux collections) sera fait à l'intérieur d'une méthode annotée avec @Transactional.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top