Buscar
Social
Ofertas laborales ES

Foro sobre Java EE > org.hibernate.LazyInitializationException - could not initialize proxy - no Session

Buen día,

Tengo un inconveniente, en un desarrollo web que estoy realizando.
Estoy usando :
Hibernate, Java, servicios web.

Tengo 2 proyectos:

1.-ServicioWeb .-Contiene los webservices
2.-Cliente .- consume los webservices

ServicioWeb
Este proyecto posee las entidades.java, entidades.hbm.xml, las configuraciones hibernate.cfg.xml y hibernate.reveng.xml

Por ejemplo:
Tengo la entidad SairBriAcciones que está relacionada con la entidad SairBriEstatus :


public class SairBriAcciones implements java.io.Serializable {

private BigDecimal idAccion;
private SairBriEstatus sairBriEstatus;
private SairBriBrief sairBriBrief;
private String accion;
private Date fecha;
private Set sairBriAccionAreas = new HashSet(0);

public SairBriAcciones() {
}

public SairBriAcciones(BigDecimal idAccion) {
this.idAccion = idAccion;
}

public SairBriAcciones(BigDecimal idAccion, SairBriEstatus sairBriEstatus,
SairBriBrief sairBriBrief, String accion, Date fecha,
Set sairBriAccionAreas) {
this.idAccion = idAccion;
this.sairBriEstatus = sairBriEstatus;
this.sairBriBrief = sairBriBrief;
this.accion = accion;
this.fecha = fecha;
this.sairBriAccionAreas = sairBriAccionAreas;
}

public BigDecimal getIdAccion() {
return this.idAccion;
}

public void setIdAccion(BigDecimal idAccion) {
this.idAccion = idAccion;
}

public SairBriEstatus getSairBriEstatus() {
return this.sairBriEstatus;
}

public void setSairBriEstatus(SairBriEstatus sairBriEstatus) {
this.sairBriEstatus = sairBriEstatus;
}

public SairBriBrief getSairBriBrief() {
return this.sairBriBrief;
}

public void setSairBriBrief(SairBriBrief sairBriBrief) {
this.sairBriBrief = sairBriBrief;
}

public String getAccion() {
return this.accion;
}

public void setAccion(String accion) {
this.accion = accion;
}

public Date getFecha() {
return this.fecha;
}

public void setFecha(Date fecha) {
this.fecha = fecha;
}

public Set getSairBriAccionAreas() {
return this.sairBriAccionAreas;
}

public void setSairBriAccionAreas(Set sairBriAccionAreas) {
this.sairBriAccionAreas = sairBriAccionAreas;
}

}



<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 01/12/2016 12:38:37 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="ec.com.rgt.sair.hbm.SairBriAcciones" table="SAIR_BRI_ACCIONES" schema="USRSAIR">

<column name="ID_ACCION" precision="22" scale="0" />
<generator class="assigned" />

<many-to-one name="sairBriEstatus" class="ec.com.rgt.sair.hbm.SairBriEstatus" fetch="select" >
<column name="ID_ESTATUS" precision="22" scale="0" />
</many-to-one>
<many-to-one name="sairBriBrief" class="ec.com.rgt.sair.hbm.SairBriBrief" fetch="select" >
<column name="ID_BRIEF" precision="22" scale="0" />
</many-to-one>
<property name="accion" type="string">
<column name="ACCION" length="200" />
</property>
<property name="fecha" type="date">
<column name="FECHA" length="7" />
</property>
</class>
</hibernate-mapping>

Tengo una clase prueba en el proyecto ServicioWeb para probar si funciona la consulta, la cual es la siguiente:


public class Prueba {

public static void main(String[] args) {
DAO dao=new DAO();
List<SairBriAcciones> list=dao.find("from SairBriAcciones a ");
for (SairBriAcciones acciones : list) {
System.out.println(acciones.getAccion());//Si consulta
}
}

}


La prueba anterior si me funciona y me muestra la información, pero cunando agrego la siguiente linea, salta la excepción org.hibernate.LazyInitializationException: could not initialize proxy - no Session:

public class Prueba {

public static void main(String[] args) {
DAO dao=new DAO();
List<SairBriAcciones> list=dao.find("from SairBriAcciones a ");
for (SairBriAcciones acciones : list) {
System.out.println(acciones.getAccion());
System.out.println(acciones.getSairBriEstatus().getNombre());//Se agrega esta linea para consultar la relación
}
}

}


La excepción es la siguiente:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at ec.com.rgt.sair.hbm.SairBriEstatus_$$_javassist_91.getNombre(SairBriEstatus_$$_javassist_91.java)
at ec.com.rgt.sair.controller.Prueba.main(Prueba.java:16)

Así que investigue, investigue ,investigue ... y encontre 2 soluciones:
<ol><li>Usar join fetch en las consultas cuando se desea consultar alguna entidad relacionada</li>

List<SairBriAcciones> list=dao.find("from SairBriAcciones a join fetch a.sairBriEstatus ");//Se agrega el join fetch

<li>Activar el atributo lazy="false" en el archivo </li></ol>

<many-to-one name="sairBriEstatus" class="ec.com.rgt.sair.hbm.SairBriEstatus" fetch="select" lazy="false">
<column name="ID_ESTATUS" precision="22" scale="0" />
</many-to-one>

Probé ambas y funcionaron, asi que decidi utilizar la primera porque la segunda opción (según lo que investigue) siempre te trae la información de la entidad relacionada haciendo que el rendimiento sea vea afectado, en cambio la primera solo se trae la información cuando usas el join fetch.

Por ejemplo de las dos clases pruebas anteriores:
Aplicando la primera solución para la consulta sin el join fetch, esta solo trae la tabla la información de SairBriAcciones y no la SairBriEstatus(estaría bien porque solo necesito la tabla SairBriAcciones ), para la segunda consulta aplicando el join fetch trae la información de ambas SairBriAcciones y SairBriEstatus porque yo se lo dije que la traiga por medio del join fetch.
Ahora aplicando la segunda solución del atributo lazy="false" para la consulta sin el join fetch este trae la información de ambas tablas SairBriAcciones y SairBriEstatus, entonces aqui es donde el redimiento se ve afectado porque no necesito la informacion de la tabla SairBriEstatus porque solo necesito la de SairBriAcciones, pero el atributo lazy="false" significa que siempre la va atraer.
Bueno eso fue lo que aprendí investigando y lo confirme con las pruebas.

Pero el problema viene en el otro proyecto.


Este el método de consulta que proporcione para que el otro proyecto(Cliente) lo consuma:


@WebMethod(operationName = "consulta_acciones")
public List<SairBriAcciones> consulta_acciones(String hql){
@SuppressWarnings("unchecked")
List<SairBriAcciones> list=dao.find(hql);
return list;
}

Cliente
Este proyecto consume el método consulta_acciones que proporcione del proyecto ServicioWeb.
También posee la clase prueba.

Este es el método para consumir el servicioweb:


public class ServiciosWeb {
private static WsBriefService locator = new WsBriefService();
private static WsBrief brief=locator.getWsBriefPort();

public List<SairBriAcciones> consultaAcciones(String hql){
List<SairBriAcciones> acciones= brief.consultaAcciones(hql);
return acciones;
}
}

Entonces realizando la misma prueba (en el Cliente):


public static void main(String[] args) throws ParseException {
ServiciosWeb web=new ServiciosWeb();
List<SairBriAcciones> list=web.consultaAcciones("from SairBriAcciones a ");
for (SairBriAcciones acciones : list) {
System.out.println(acciones.getAccion());
}
}

Obtengo otra vez el error:


Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Marshalling Error: could not initialize proxy - no Session
at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(Unknown Source)
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(Unknown Source)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(Unknown Source)
at com.sun.proxy.$Proxy30.consultaAcciones(Unknown Source)
at ec.com.rgt.sair.brief.ServiciosWeb.consultaAcciones(ServiciosWeb.java:126)
at ec.com.rgt.sair.util.Prueba.main(Prueba.java:108)

Pero si agrego el join fetch a la relación sige saltanto la excepción, para que no salte tengo que agregar el join fetch a todas las relaciones(son 2 relaciones "SairBriEstatus y SairBriBrief" que tiene la tabla SairBriAcciones) pero estaria haciendo lo mismo que el atributo lazy="false".

Lo que deseo es que solo traiga la información de la tabla SairBriAcciones, pero no lo consigo tengo usar todos los join fetch en todas las relaciones o utilizar el atributo lazy="false" para conseguirlo, pero el rendimiento de mi aplicación baja muchisimo.

Entonces deseo saber si alguien a pasado por este problema y como lo soluciono.
Repito deseo lo la información de la tabla SairBriAcciones en el Cliente sin activar la carga de las demás tablas.

DAO:

public class DAO {
public static Session currentSession() {
return HibernateUtiles.getSessionFactory().openSession();
}
public static Session getSession() {
return currentSession();
}
public List find(String hql) {
List lista = null;
Session sess = getSession();
try {
sess.beginTransaction();
Query query = sess.createQuery(hql);
lista = query.list();
sess.getTransaction().commit();
} catch (QueryException e) {
// TODO: handle exception
UtilsDAO dao=new UtilsDAO();
dao.savelog("DAO", "DAO", "find", "QueryException", 49, e.getMessage()+ " "+hql, "SEGURIDAD", 3);
}finally{
if(sess!=null)
sess.close();
}
return lista;
}

HibernateUtiles:


public class HibernateUtiles {
public static final SessionFactory sessionFactory;
static {
try {
Configuration classicConf = new Configuration().configure();
sessionFactory = classicConf.buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}

Saludos.

marzo 13, 2017 | Registered Commenterssan92

Tu problema es muy típico. Estas consultando una tabla pero no te traes sus relaciones. Luego, consultas esa relación y te salta el LazyInitializationException.
La solución más evidente es lo que estás haciendo, en la consulta te traes las relaciones con el left join fetch.
Existen otras opciones, definir un Persistence context del tipo PersistenceContextType.EXTENDED o pasarte a EclipseLink que te evita este tipo de errores.
Mi recomendación es que te centres en el problema. Haces una consulta de la cual no te traes las relaciones que luego necesitas, ergo traete las relaciones en la consulta. Es más rápido y óptimo que las demás soluciones.

marzo 16, 2017 | Unregistered CommenterAbel