org.hibernate.LazyInitializationException: Como usar corretamente o recurso de carregamento lento do Hibernate

Eu tive alguns problemas ao carregar uma lista de objetos do meu banco de dados usando o Hibernate e o modo preguiçoso = true. Espero que alguém possa me ajudar aqu

Eu tenho uma classe simples aqui chamada UserAccount que se parece com isso:

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

Estou mapeando esta classe no Hibernate através do seguinte arquivo de mapeamento:

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

Como você pode ver, o preguiçoso está definido como "true" no elemento de mapeamento de mala

Salvar os dados no banco de dados funciona bem:

@Loading também funciona chamandoloadUserAccount(String username) (veja o código abaixo):

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

O problema é justo: quando eu acesso elementos na lista "mailAccounts", recebo a seguinte exceção:

org.hibernate.LazyInitializationException: falha ao inicializar preguiçosamente uma coleção de funções: test.account.UserAccount.mailAccounts, nenhuma sessão ou sessão foi fechada

Presumo que o motivo dessa exceção seja que a sessão foi fechada (não sei por que e como) e, portanto, o Hibernate não pode carregar a lista. Como você pode ver, eu até removi osession.close() chamada doloadUserAccount(), mas a sessão ainda parece ser fechada ou substituída por outra instância. Se eu definirlazy=false, tudo funciona perfeitamente, mas não é isso que eu queria, porque preciso do recurso de carregar dados "sob demanda" devido a problemas de desempenh

Assim, se não tiver certeza de que minha sessão ainda é válida após o métodoloadUserAccount(String username) encerrado, qual é o sentido de ter esse recurso e como faço para solucionar isso?

Obrigado pela ajuda

Ps: eu sou iniciante no Hibernate, então desculpe meu noobishnes

Atualizar Aqui está o meu hibernate 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>

questionAnswers(3)

yourAnswerToTheQuestion