org.hibernate.LazyInitializationException: Cómo usar correctamente la función de carga diferida de Hibernate
Tengo problemas para cargar una lista de objetos de mi base de datos usando Hibernate y lazy = true mode. Espero que alguien pueda ayudarme aquí.
Tengo una clase simple llamada UserAccount que se ve así:
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;
}
}
Estoy mapeando esta clase en Hibernate a través del siguiente archivo de mapeo:
<?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>
omo puede ver, perezoso se establece en "verdadero" en el elemento de mapeo de bolsas.
Guardar los datos en la base de datos funciona bien:
Loading también funciona llamando aloadUserAccount(String username)
(vea el código a continuación):
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;
}
}
El problema es solo: cuando accedo a elementos dentro de la lista "mailAccounts", obtengo la siguiente excepción:
org.hibernate.LazyInitializationException: no se pudo inicializar perezosamente una colección de roles: test.account.UserAccount.mailAccounts, no se cerró ninguna sesión o sesión
Supongo que la razón de esta excepción es que la sesión se cerró (no sé por qué y cómo) y, por lo tanto, Hibernate no puede cargar la lista. Como puede ver, incluso eliminé lasession.close()
llamada de laloadUserAccount()
pero la sesión parece estar cerrada o reemplazada por otra instancia. Si configurolazy=false
, entonces todo funciona sin problemas, pero esto no es lo que quería porque necesito la función de cargar datos "a pedido" debido a problemas de rendimiento.
Entonces, si no puedo estar seguro de que mi sesión sigue siendo válida después del métodoloadUserAccount(String username)
terminado, ¿cuál es el punto de tener esa característica y cómo puedo solucionarla?
¡Gracias por tu ayuda
Ps: Soy un principiante de Hibernate, así que disculpe mi novato.
Actualizar Aquí está mi 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>