2013-03-05 8 views
6

Mi sembra di avere un problema piuttosto strano. Visualizzo gli utenti e i loro ruoli in un JSP. Per qualche motivo, i ruoli vengono visualizzati solo per la prima volta che la pagina viene caricata. Aggiorna la pagina e i ruoli vengono tutti cancellati dal database!Perché Hibernate sta eliminando le mie voci della raccolta quando tutto ciò che faccio è un elenco?

La mia configurazione è l'applicazione standard Spring MVC, JPA + Hibernate (over Spring Data). (3.2.x Spring, Hibernate 4.1.8)

Ho due soggetti - User e Role come illustrato di seguito (assumere il setter e getter)

@Entity 
public class User { 
    @Id 
    @GeneratedValue 
    private int id; 

    private String name; 

    @ManyToMany 
    @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) 
    private Set<Role> roles = new HashSet<>(); 
} 

@Entity 
public class Role { 
    @Id 
    private String id; 

    private String name; 
} 

ho un repository primavera dati che non lo fa definire eventuali metodi aggiuntivi.

public interface UserRepository extends CrudRepository<User, Integer> { 
} 

Ho un servizio e un controller i cui metodi rilevanti sono i seguenti.

// service 
@Transactional(readOnly = true) 
public Iterable<User> findAll() { 
    return userRepository.findAll(); 
} 

// controller 
@RequestMapping 
public String showUsers(ModelMap model) { 
    model.put("users", userService.findAll()); 

    return "admin/users"; 
} 

Nel mio JSP, sto cercando di visualizzare tutti gli utenti e tutti i ruoli associati.

<c:forEach var="user" items="${users}"> 
    <tr> 
     <td>${user.name}</td> 
     <td> 
      <c:forEach var="role" items="${user.roles}"> 
       ${role.name} 
      </c:forEach> 
     </td> 
    </tr> 
</c:forEach> 

Come ho detto prima, i record nella mia user_role tabella vengono eliminati dopo questa pagina è stato reso.

Su consentendo DEBUG per org.hibernate e consentendo la registrazione di query, ecco quello che ho trovato nei log:

22:36:25 DEBUG Collection dereferenced: [com.adarshr.domain.User.roles#1] [Collections.java:76] 
22:36:25 DEBUG Flushed: 0 insertions, 0 updates, 0 deletions to 2 objects [AbstractFlushingEventListener.java:117] 
22:36:25 DEBUG Flushed: 0 (re)creations, 0 updates, 1 removals to 1 collections [AbstractFlushingEventListener.java:124] 
22:36:25 DEBUG Deleting collection: [com.adarshr.domain.User.roles#1] [AbstractCollectionPersister.java:1124] 
22:36:25 DEBUG 
    delete 
    from 
     user_role 
    where 
     user_id=? [SqlStatementLogger.java:104] 
22:36:25 DEBUG Done deleting collection [AbstractCollectionPersister.java:1182] 

Chiaramente qualcosa di strano sta succedendo qui. Perché la mia collezione viene deferita in primo luogo?

Ecco la definizione del mio gestore di entità JPA.

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="mainDataSource" /> 
    <property name="packagesToScan" value="com.adarshr.domain" /> 
    <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" /> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
    </property> 
    <property name="jpaProperties"> 
     <value> 
      hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect 
      hibernate.format_sql=${hibernate.format.sql} 
      hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy 
      hibernate.show_sql=${hibernate.show.sql} 
      hibernate.enable_lazy_load_no_trans=true 
     </value> 
    </property> 
</bean> 

Mi manca qualcosa di ovvio qui?

+0

Da dove hai ricevuto "enable_lazy_load_no_trans"? Tutto quello che posso trovare su di esso è la gente che dice che è bacato e non raccomandato per l'uso. –

+0

Da http://stackoverflow.com/questions/578433/how-to-solve-lazy-initialization-exception-using-jpa-and-hibernate-as-provider – adarshr

+0

"Usare con cautela è un eufemismo!" "Questa è davvero solo una funzione mirata al benchmark ..." "... questa è una pessima idea negli usi generali." "usare a proprio rischio". "... non è una caratteristica che pensiamo davvero che le persone dovrebbero usare senza conoscere le possibili conseguenze." https://hibernate.onjira.com/browse/HHH-7457 Hmm, stai percependo un tema lì? Non usarlo –

risposta

5

Come il codice che hai postato sembra corretto, sto indovinando qui.

La prima cosa che vorrei suggerire è di rimuovere questa inizializzazione (sembra l'unico posto dove vengono rimossi i ruoli) che mentre è una buona idea di per sé in generale (vedi commenti sotto) penso che possa interferire con hibernate.enable_lazy_load_no_trans=true che è stato noto per leak connections in passato:

private Set<Role> roles = new HashSet<>(); 

Un secondo tentativo sarebbe quello di verificare se e quali cambiamenti se anche annotare il lato inverso della tua relazione con ManyToMany mappedBy.

Un terzo tentativo potrebbe essere se caricando avidamente la raccolta risolve il problema (aggravando la posizione enable_lazy_load_no_trans ancora di più), utilizzando FetchType, Hibernate.initialize() di qualunque cosa si desideri.

ultimo è sbarazzarsi di enable_lazy_load_no_trans e utilizzare OpenSessionInView

EDIT: ahh, ultimo, si può * avere questo bug (hibernate 4.1.8 e 4.1.9 colpiti): https://hibernate.onjira.com/browse/HHH-7971

Quindi avere una possibilità con 4.1.7 potrebbe dare risultati migliori (o forse peggio).

* dove può essere inteso come: "il tuo caso è così simile che sei invitato a inviare il tuo codice come test case nella segnalazione di bug".

+0

Cattiva idea. * Sempre * inizializza i tipi di raccolta in una raccolta vuota. Garantisco che questa non è la causa principale. –

+0

@Ryan Stewart Sono d'accordo, la mia idea potrebbe essere un problema con hibernate.enable_lazy_load_no_trans = true e stavo dando una possibilità. –

+0

Ho appena visto il bug report. Ho esattamente lo stesso problema. Proverò a inviare un test case. Il downgrade a 4.1.7 sembrava risolvere il problema. Tuttavia, non avere la collezione inizializzata non ha fatto la differenza. Anche avere un OEMIVFilter ha funzionato. – adarshr

Problemi correlati