2010-03-15 19 views
7

Correggimi se qualcosa non va.DAO, Spring and Hibernate

Ora, quando utilizziamo Spring DAO per i modelli ORM, quando usiamo l'attributo @Transactional, , non abbiamo il controllo sulla transazione e/o sulla sessione quando il metodo è chiamato esternamente, non all'interno del metodo.

Il caricamento lento consente di risparmiare risorse: meno query al db, meno memoria per mantenere tutte le raccolte recuperate nella memoria dell'app.

Quindi, se lazy = false, quindi viene recuperato tutto, tutte le raccolte associate, che non è efficace, se ci sono 10.000 record in un set collegato.

Ora, ho un metodo in una classe DAO che dovrebbe restituirmi un oggetto Utente. Dispone di raccolte che rappresentano tabelle collegate del database. Ho bisogno di ottenere un oggetto da id e quindi interrogare le sue collezioni.

Hibernate "l'inizializzazione fallita per inizializzare una raccolta in modo lento" si verifica quando si tenta di accedere alla raccolta collegata restituita da questo metodo DAO.

Spiegare per favore, che cosa è una soluzione qui?

Aggiornamento: Va bene, lascia che ti chieda questo. DAO è un livello astratto, quindi un metodo "getUserById (Integer id)" dovrebbe restituire un oggetto.

Cosa succede se in alcuni casi ho bisogno di queste raccolte collegate dell'oggetto Utente e in altre situazioni ho bisogno di quelle raccolte.

ci sono solo due modi: 1) lazy loading = false 2) creare diversi metodi: getUserByIdWithTheseCollections(), getUserByIdWithOtherCollections() e all'interno di questi metodi usare il tuo approccio?

Voglio dire, ci sono solo 2 modi e niente di meglio?

Aggiornamento 2: Spiegare per favore, cosa mi darebbe l'uso esplicito di SESSIONFACTORY? Come appare in pratica? Creiamo un'istanza dell'oggetto DAO, , quindi l'inseriamo con la sessione di produzione e questo significherebbe che due chiamate di metodo consecutive a DAO verranno eseguite all'interno della stessa transazione? Mi sembra comunque che DAO sia distaccato dalle classi che ne fanno uso!

La logica e le transazioni sono incapsulate all'interno di DAO, giusto?

risposta

6

è possibile ottenere la collezione legata a transazioni per caricarlo mentre siete ancora all'interno della transazione:

User user = sessionFactory.getCurrentSession().get(User.class, userId); 
user.getLinkedCollection().size(); 
return user; 

Come BalusC ha fatto notare, è possibile utilizzare al posto di Hibernate.initialize()size(). È molto più pulito.

Quindi quando si restituisce una tale entità, il campo pigro è già inizializzato.

Rispondere al PS - utilizza le transazioni a livello di servizio (piuttosto che DAO) fattibile? Sembra essere, come fare ogni chiamata DAO in una transazione separata sembra essere uno spreco (e potrebbe essere errato).

+0

@Konrad Garus Si prega di vedere il mio poscritto della domanda, qui il testo è meno leggibile, quindi vi chiedo lì. – EugeneP

+0

@EugeneP Vedi risposta aggiornata. –

5

Trovo che sia meglio mettere @Transactional sul livello di servizio, piuttosto che sul livello DAO. Altrimenti, tutte le tue chiamate DAO si trovano in sessioni di sospensione separate: tutto ciò che l'uguaglianza degli oggetti non funzionerà.

+1

Questo è un buon modo per affrontarlo quando si lavora con SpringDAO. –

1

A mio parere il modo migliore per risolvere questo problema sarà progettare un'applicazione in un modello sessione per richiesta. Quindi, se hai un oggetto preso da DAO, finché il tuo pattern OSIV non funziona, puoi usare l'oggetto in modo sicuro ovunque nell'applicazione, anche nelle viste senza disturbare questa roba. Questo è probabilmente migliore soluzione che quelli proposti, perché:

  1. Hibernate.initialize() o la dimensione è una soluzione molto artificiale - che cosa se si vuole avere l'utente con diversi raccolta inizializzato, vuoi scrivere un altro metodo per ottenere utente?
  2. Servizio strato modello transazionale è OK, ma lo stesso problema nasce quando si desidera ottenere oggetto estratto dal livello di servizio di utilizzarlo in controller o vista
1

Si potrebbe fare qualcosa di simile a seguente:

public User getByUserId(Long id, String ... fetch) { 
    Criteria criteria = createCriteria(); 

    if (fetch != null) { 
     for (String fieldName : fetch) { 
      criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly 
     } 
    } 
    return criteria.add(Restrictions.eq("id", id)).list(); 
}