org.mise en veille prolongée.LazyInitializationException: Comment utiliser correctement les Hibernate fonctionnalité de chargement différé

J'ai eu quelques problèmes pour charger une liste d'objets à partir de ma base de données en utilisant Hibernate et paresseux=true mode.
Espérons que quelqu'un pourra m'aider ici.

J'ai une classe simple appelé ici Compteutilisateur qui ressemble à ceci:

public class UserAccount {
    long id;
    String username;
    List<MailAccount> mailAccounts = new Vector<MailAccount>();

    public UserAccount(){
        super();
    }

    public long getId(){
        return id;
    }

    public void setId(long id){
        this.id = id;
    }

    public String getUsername(){
        return username;
    }

    public void setUsername(String username){
        this.username = username;
    }

    public List<MailAccount> getMailAccounts() {
        if (mailAccounts == null) {
            mailAccounts = new Vector<MailAccount>();
        }
        return mailAccounts;
    }

    public void setMailAccounts(List<MailAccount> mailAccounts) {
        this.mailAccounts = mailAccounts;
    }
}

Je suis cartographie de cette classe dans Hibernate par le fichier de mappage:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="test.account.UserAccount" table="USERACCOUNT">

        <id name="id" type="long" access="field">
            <column name="USER_ACCOUNT_ID" />
            <generator class="native" />
        </id>

        <property name="username" />

        <bag name="mailAccounts" table="MAILACCOUNTS" lazy="true" inverse="true" cascade="all">
            <key column="USER_ACCOUNT_ID"></key>
            <one-to-many class="test.account.MailAccount" />
        </bag>

    </class>
</hibernate-mapping>

Comme vous pouvez le voir, le paresseux est définie sur "true" dans le sac de cartographie de l'élément.

L'enregistrement de données dans la base de données fonctionne correctement:

Chargement fonctionne aussi en appelant loadUserAccount(String username) (voir code ci-dessous):

public class HibernateController implements DatabaseController {
private Session                 session         = null;
private final SessionFactory    sessionFactory  = buildSessionFactory();
public HibernateController() {
super();
}
private SessionFactory buildSessionFactory() {
try {
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public UserAccount loadUserAccount(String username) throws FailedDatabaseOperationException {
UserAccount account = null;
Session session = null;
Transaction transaction = null;
try {
session = getSession();
transaction = session.beginTransaction();
Query query = session.createQuery("FROM UserAccount WHERE username = :uname").setParameter("uname", username));
account = (UserAccount) query.uniqueResult();
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw new FailedDatabaseOperationException(e);
} finally {
if (session.isOpen()) {
//session.close();
}
}
return account;
}
private Session getSession() {
if (session == null){
session = getSessionFactory().getCurrentSession();
}
return session;
}
}

Le problème est là: Quand j'ai accès à des éléments dans la liste "mailAccounts", j'obtiens l'exception suivante:

org.mise en veille prolongée.LazyInitializationException:
échoué paresseusement initialiser un
collection de rôle:
test.compte.Compteutilisateur.mailAccounts,
pas de session ou la session a été fermée

Je suppose que la raison de cette exception est que la session est fermé (je ne sais pas pourquoi et comment) et donc, Hibernate ne peut pas charger la liste.
Comme vous pouvez le voir, j'ai même retiré la session.close() appel de la loadUserAccount() méthode, mais la session semble toujours être fermé ou remplacée par une autre instance.
Si j'ai mis lazy=false, alors tout fonctionne en douceur, mais ce n'est pas ce que je voulais parce que j'ai besoin de la fonction de chargement de données "à la demande" en raison de problèmes de performances.

Donc, si je ne peux pas être sûr que ma session est toujours valide après la méthode loadUserAccount(String username) résilié, ce qui est le point d'avoir cette fonctionnalité et comment puis-je contourner cela?

Merci pour votre aide!

Ps: je suis un Hibernate débutant s'il vous plaît excuser mon noobishness.

Mise à jour: Voici mon hibernation config.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">foo</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mytable</property>
<property name="hibernate.connection.username">user</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<!-- Auto create tables -->
<!--        <property name="hbm2ddl.auto">create</property>-->
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Mappings -->
<mapping resource="test/account/SmampiAccount.hbm.xml"/>
<mapping resource="test/account/MailAccount.hbm.xml"/>
</session-factory>
</hibernate-configuration>

OriginalL'auteur Timo | 2011-04-29