2012-12-02 14 views
7

Foo aspetto ha questo in esso:org.hibernate.LazyInitializationException: impossibile inizializzare la procura - nessuna sessione, encore un fois

@ManyToMany 
private Set<User> favouritedBy; 

mentre l'utente ha questo:

@ManyToMany(mappedBy = "favouritedBy") 
private Set<Foo> favourites = new HashSet<Foo>(); 
public Set<Foo> getFavourites() { 
    return favourite; 
} 

E fooService ha questo , con la collezione lazyloaded a cui si accede mentre la sessione è aperta, tramite il metodo tranactional:

@Transactional(readOnly = true) 
public Set<Foo> getFavourites(User user) { 
user = dao.get(User.class, user.getId()); //the dao gets a session 
Set<Foo> favourites = user.getFavourites();//but the session is not here and the exception is thrown? 
return favourties; 
} 

EDIT Questo lo fissa, senza l'utilizzo di criteri:

Set<Foo> favourites = new HashSet<Foo>(user.getFavourites()); 

e questo lo fissa con criteri

Session session = sessionFactory.getCurrentSession(); 
final Criteria crit = session.createCriteria(Foo.class); 
crit.setFetchMode("favourites", FetchMode.JOIN); 
crit.add(Property.forName("id").eq(id)); 
return (Foo) crit.uniqueResult(); 
+0

siete sicuri di aver 'transactionManager' impostato nel contesto primavera e' tx: definito da annotation? – hoaz

+0

sì, tutto funziona bene ovunque ... – NimChimpsky

+0

puoi pubblicare traccia dello stack qui? controlleremo se il codice di gestione delle transazioni è lì – hoaz

risposta

8

Il predefinite FetchType in una ManyToMany è LAZY e la documentazione di sospensione per working with lazy associations richiede chiaramente questo tipo di accesso come errore. È possibile interagire con oggetti associati pigramente solo mentre la sessione è ancora aperta. Questa parte della documentazione fornisce anche delle alternative per accedere a tali membri pigramente associati di un oggetto. Noi preferiamo per specificare la modalità Visualizza come JOIN nei criteri utilizzati, nelle nostre applicazioni

Modifica:

Set<Foo> favourites = user.getFavourites(); 

La dichiarazione di cui sopra in realtà non restituire un insieme che contiene tutti i Foo oggetti. È solo un proxy. Gli oggetti attuali vengono recuperati solo quando si accede agli elementi nel set come favorites.iterator(), ecc. Questa operazione sta chiaramente accadendo al di fuori del proprio metodo getFavorites(). Ma l'annotazione @Transactional sul metodo getFavorites() indica che la sessione verrà chiusa alla fine di questo metodo.

Quindi, quando i metodi vengono chiamati sul set di preferiti, la sessione è già chiusa e quindi l'eccezione.

Per risolvere questo problema, è necessario utilizzare un oggetto Criteria per recuperare l'utente e specificare il tipo di recupero come JOIN in modo che gli oggetti Foo vengano popolati nell'oggetto Utente restituito.

+0

sì, ho pensato che la sessione è ancora aperta, ma questo è il problema in quanto il metodo è transazionale e utilizza dao che ha inserito la sessione in esso. – NimChimpsky

+0

Nel momento in cui il tuo set pigramente associato viene copiato per essere disponibile per il chiamante del metodo 'getFavorites()', la sessione sarebbe già chiusa, poiché l'ambito della transazione termina alla fine del metodo 'getFavorites()' . – Vikdor

+0

Non capisco affatto. "l'ambito della transazione termina alla fine di getFavorites()" questo è quando voglio che finisca, ho chiamato user.getFavourties mentre la sessione è aperta, caricherà da db i dati e popolerà un hashset? (beh ovviamente non funziona e ho torto, vorrei sinceramente non aver mai disturbato con l'ibernazione) – NimChimpsky

0

Sì, è necessario accedere all'oggetto nel contesto transnazionale altrimenti verrà generato un LazyInitializationException.

6

Esistono due soluzioni.

  1. Non utilizzare il carico lento.

    Impostare lazy=false in XML o Set @OneToMany(fetch = FetchType.EAGER) Nell'annotazione.

  2. Utilizzare il carico lento.

    Set lazy=true in XML o Set @OneToMany(fetch = FetchType.LAZY) Nell'annotazione.

    e aggiungere filtri nel vostro web.xml

    <listener> 
        ... 
    </listener> 
    <filter> 
        <filter-name>hibernateFilter</filter-name> 
        <filter-class> 
         org.springframework.orm.hibernate4.support.OpenSessionInViewFilter 
        </filter-class> 
        <init-param> 
         <param-name>sessionFactoryBeanName</param-name> 
         <param-value>mySessionFactory</param-value> 
        </init-param> 
    </filter> 
    <filter-mapping> 
        <filter-name>hibernateFilter</filter-name> 
        <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    <servlet> 
        ... 
    </servlet> 
    

E <param-value>mySessionFactory</param-value> è il vostro nome di fagioli sessionFacory che ha definito in applicationContext.xml

+0

Questo articolo discute queste soluzioni proposte: https://vladmihalcea.com/the-best-way-to-handle-the-lazyinitializationexception/ – olivmir

Problemi correlati