style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

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:

  • ServicioWeb .-Contiene los webservices
  • 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">
            <id name="idAccion" type="big_decimal">
                <column name="ID_ACCION" precision="22" scale="0" />
                <generator class="assigned" />
            </id>
            <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:

    1. Usar join fetch en las consultas cuando se desea consultar alguna entidad relacionada
    2. List<SairBriAcciones> list=dao.find("from SairBriAcciones a join fetch a.sairBriEstatus ");//Se agrega el join fetch

    3. Activar el atributo lazy="false" en el archivo
    <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.

    Saludos.

    Opciones de visualización de comentarios

    Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

    Ciclo de vida de la session

    No logro ubicar en donde estás usando la Session de hibernate, pero, si me ha pasado, hay que tener mucho cuidado con el manejo de la session y más si usas la carga de los atributos de la entidad con el tipo Lazy, es posible que estés cerrando la session explicitamento o implicitamente y mucho después accedas a los atributos de la entidad.

    Imagen de ssan92

    DAO: public class DAO

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

    }

    Solo pasa en el Cliente, pero si coloco el atributo lazy="false" o uso los join fetch en todas las relaciones, hay si consulta.
    Pero solo quiero consultar una tabla como la clase prueba del primer proyecto.

    Imagen de ssan92

    El atributo lazy es lo que no

    El atributo lazy es lo que no deseo usar, pero para que pueda consultar el query en el cliente me obliga a usarlo, xq si no no sale la consulta

    Imagen de neko069

    Hibernate.initialize

    Puedes usar:

    Hibernate.initialize(objeto.objetoAnidadoOColeccion);

    Y luego ya puedes acceder a los atributos de tu objeto (que se supone representa la relación con otra tabla) o bien una colección.

    O puedes investigar como usar la implementación de Hibernate Open session in view.

    Ambas soluciones son unos parches horrendos, pero servirán para lo que necesitas.

    Deja la consulta preparada

    Si o si tendiras que utilizar los fetch de tu consulta, aunque parezca que estas haciendo lo mismo con el EAGER no es así, el EAGER implica que para TODAS las consultas que hagas se tendra que traer la información, SIMPRE, esto afectara a todas las consultas posteriores que hagan mencion a esa entidad.

    No dejes que el cliente tire las consultas que el quiera a tu base de datos, en lugar de eso dejale las consultas preparadas, es decir dejale algo asi como getSairBriAcciones() y getSairBriAccionesFetchLaOtraTabla().

    Usar la carga EAGER es la ultima opción que te daría debido a que es implicará que todas las consultas futuras iran por la información y tendrias un problema de rendimiento aun mayor al que mencionas ahora, si lo dejas como LAZY pues tienes espacio para maniobrar.

    Por favor crea código respetando el estilo de java, es decir los metodos se nombranAsi(conCamelCase).

    El que tu abras la transacción y la cierres de forma manual es una mala practica debido a que tu tienes que asumir esa responsabilidad, ¿que pasaria si necesitas usar exactamente el mismo metodo pero en otro metodo donde ya se abre y se cierra una transacción?, el @Transactional es tu amigo.

    style="display:inline-block;width:728px;height:90px"
    data-ad-client="ca-pub-5164839828746352"
    data-ad-slot="7563230308">