Problemas con Hibernate

Hola a todos tengo un problema con hibernate, aclarando que estoy empezando con este framework. Ya mapee mi Base de Datos creando mis beans y mis pojos(archivos .java y hbm). Tengo poblemas al consultar los datos de una tabla en especial que tiene referencias a otras tablas del tipo many-to-one. El problema es que al consultar los datos de las tablas a las que hace referencia me manda la siguiente excepcion:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session .

Estuve investigando y hablan sobre cambiar las propiedades del lazy = false en mis archivos hbm, ya lo hice y no funciono, tambien agregue la anotacion @Proxy( lazy=true ) en mis archivos .java y tampoco funciona. Espero que alguien me pueda ayudar.

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.

¿Estás usando Spring?

Ese error es típico cuando se usa Spring con Hibernate.

No

No, no estoy usando Spring. Uso JSP en la capa vista, servlets en la capa control y Hibernate en el modelo. Genere los beans y los pojos usando el IDE NetBeans 6.5

Imagen de ezamudio

Hibernate 3.3?

Si estás usando hibernate 3.3, puedes definir todas tus entidades y relaciones con puras anotaciones, y así te ahorras los .hbm y tienes menos archivos que mantener (de todas maneras necesitas las clases en Java así que por qué no definir ahi todo de una vez).

Tu problema es porque lees un objeto de una entidad que tiene relación a muchos con otra entidad, el típico maestro-detalle, pero solamente leíste el maestro, que se queda con un falso arreglo en la relación al detalle, que sirve para que una Session de hibernate pueda sustituirlo por un arreglo ya con los detalles. Pero seguramente tienes un DAO o algo similar que lee el objeto, cierra la sesión, lo devuelve, y a la hora que lo quieres desplegar en tu JSP te sale esa excepción porque se intenta resolver el arreglo que nada más está de placeholder y no se puede porque no hay una sesión abierta.

Una manera de resolver esto es el patrón "open session in view" que consiste en que se abra una sesión de hibernate cuando se está rendereando un JSP (o página web con cualquier otro framework como Tapestry, JSF, etc) y cerrarlo al final. El truco está en que siempre SIEMPRE se cierre al final la sesión. Con eso se resuelve bien cualquier relación lazy y no tienes broncas. Pero busca alguna manera automática de hacerlo, probablemente Spring tiene algo con AOP para abrirte automáticamente una sesión cuando se va a renderear un JSP y la cierra al final, o alguna librería adicional de hibernate si no quieres meter Spring.

Imagen de ezamudio

lazy=true

Por cierto, estás poniendo lazy=true en la anotación de @Proxy, lo cual de por sí ya es el default. Necesitas poner lazy=false para que los detalles se obtengan de inmediato en tus beans. Pero revisa bien tu modelo porque tiene un costo en performance y memoria, no es recomendable en todos los casos porque al principio en desarrollo te vas a quitar la lata de esa excepción pero en producción ya después con más datos podrias tener muchisimas broncas de performance y memoria.

Okay, resolvamos esto

¿Tienes alguna invocación a Hibernate.initialize()?

Si no la tienes, vas a buscar en la documentación, nada de andar preguntando en foros ¿eh?. Me comprometo a ayudarte a resolver tu problema, pero a cambio debes asegurarme que ya leíste la documentación de Hibernate relacionada con "Association mappings" y también "Improving perfomance"

Estuve investigando y hablan sobre cambiar las propiedades del lazy = false en mis archivos hbm

Nada de "hablan de". Primero verifica la documentación.

Saludos cordiales

Javier Castañón

Una cosa más Javadicto

Cuando arreglemos este problema, deberás leer en el tutorial de JEE la parte relacionada con filtros, los vamos a necesitar. Con gente que está aprendiendo no soy de dar las respuestas en los foros, sino de enviarlos a leer lo que tienen que leer para que entiendan cómo funcionan las cosas.

Saludos cordiales

Javier Castañón

No tengo ninguna invocacion a Hibernate.initialize()

Hola javier, gracias por contestar ahorita mismo leo eso que dices. Perdon por hacer este tipo de preguntas en el foro pero no sabia de que otra forma contactar con alguien de ustedes para que me guiara, me podrias decir entonces que tipo de cuestiones puedo exponer en el foro?

Estoy de acuerdo

Estoy de acuerdo con lo que dices, dice el dicho dale a un hombre un pescado y comera un dia, enseñale a pescar y comera toda su vida. Gracias por contestar tan rapido, tu y Ezamudio siempre contestan a las cuestiones que hago, se nota que saben mucho y espero aprender de ustedes y posteriormente ayudar a los iniciados.

No hay problema con preguntar en los foros

Tu ya habías dicho que eres novato y estabas aprendiendo, con ese antecedente estoy más que dispuesto a colaborar porque se nota tu disposición a aprender. Cuando hayas leído esos dos capítulos podrás distinguir que en los foros se contestan muchas tonterías, por eso recomiendo no investigar en foros antes de leer la documentación.

Ahora bien, yo ya había hecho la advertencia de que si se quería algo sencillo, no se usaran cosas como Hibernate y Spring, pues en mi opinión no son ligeros, sino pesados, prácticamente igual que trabajar con componentes EJB. Ya viste el tamaño de la documentación de Hibernate, entenderás a qué me refería. Para bien o para mal, son herramientas de alta demanda en el mercado y las deberás dominar.

Saludos

Javier Castañón

Lazy =false

Hola ezamudio, entonces entiendo que puedo precindir de los archivos .hbm, sobre el performance estoy de acuerdo en que seria mas lento por que hay que subir a memoria no solo la Lista de la tabla consultada si no todos los objetos que tenga relacion con ella ( los foreign key). Pero estudiando bien el caso no habria mucho problema por que solo lo necesito para generar reportes de los mismos y no necesito mantenerla en session por mucho tiempo, ahora esta notacion solo la debo hacer con la tabla padre o tambien en todos los hijos? Otra cosa me podrias pasar un archivo de ejemplo con una tabla Padre e Hijo por favor, solo para verificar que lo estoy haciendo de la manera correcta.

RTFM!

Ditto

Ya lei lo que comentaste.

Ya lei lo que comentaste. Mapeo de asociaciones (Asociaciones unidireccionales y bidireccionales(uno a muchos, uno a uno y muchos a muchos)) y Mejorar el performance (Estrategia de captura(captura por join, por select, por subselect y por lotes)). Ya tengo una idea de como optimizar mis archivos .hbm conforme a lo que tengo en mi Base de Datos. Lo tenia por defecto con select creo que lo cambiare a join. Pero aun no entiendo como trabajar con la propiedad Lazy para las consultas haragánes. Se que no es bueno trabajar con esta filosofia por lo que comenta ezamudio, pero ahorita lo necesito para generar un reporte y no mantendre los datos en session por mucho tiempo.

Ya lei lo que comentaste.

Ya lei lo que comentaste. Mapeo de asociaciones (Asociaciones unidireccionales y bidireccionales(uno a muchos, uno a uno y muchos a muchos)) y Mejorar el performance (Estrategia de captura(captura por join, por select, por subselect y por lotes)). Ya tengo una idea de como optimizar mis archivos .hbm conforme a lo que tengo en mi Base de Datos. Lo tenia por defecto con select creo que lo cambiare a join. Pero aun no entiendo como trabajar con la propiedad Lazy para las consultas haragánes. Se que no es bueno trabajar con esta filosofia por lo que comenta ezamudio, pero ahorita lo necesito para generar un reporte y no mantendre los datos en session por mucho tiempo.

Vuelve a leer

19.1.4. Initializing collections and proxies

No estás forzado a utilizar consultas tardías.

Javier

Estoy leyendo lo que me

Estoy leyendo lo que me pediste y hablan sobre el patron "Open Session in View" y entiendo que abre la session y la mantiene durante todo el tiempo que dura el request. Para esto creo que se necesita un "servlet filter". Bueno,creo que ya le estoy dando muchas vueltas al asunto y no le avanzo, y ya necesito sacar esto y no tengo una respuesta practica asi que obtendre los datos por separado y generare el reporte. Gracias

Lo único que tienes que hacer

es asegurarte de utilizar Hibernate.initialize(). Por cierto, no publicaste los ejemplos como te sugerí: archivos de mapeo y código. ¿Cómo ayudarte si no se puede reproducir tu problema? Crear el filtro no toma más de 5 minutos. En fin, seguro que sabes mejor que los que te tratamos de guiar.

Saludos y que te salga rápido tu workaround.

No, claro que no se mas que

No, claro que no se mas que ustedes. Pero ya llevaba dos dias con lo mismo y no avanzaba, y aun me falta mucho y el tiempo es corto. Lo resolvi quitando mis archivos .hbm y solo deje los beans con las anotaciones como me indico ezamudio y deje el lazy=false. Se que no es la solucion mas optima pero me come el tiempo. Espero no te molestes y me puedas seguir guiando en este framework, me gusta toparme con gente como tu y ezamudio que conocen y saben mucho, dime con quien andas y te dire quien eres. Sale pues estamos en contacto.

Imagen de ezamudio

Reportes...

Revisa muy bien lo que quieres hacer. Es típico eso de "no hay problema porque sólo es para un reporte asi que no se quedan los objetos en memoria mucho tiempo" y da muchos más dolores de cabeza de lo que te imaginas. Cuántos usuarios concurrentes esperas tener en tu aplicación? cuántos crees que vayan a generar ese reporte u otros similares al mismo tiempo? Cuántos registros esperas que te devuelva ese reporte ya estando el sistema en producción? Obvio cuando tu lo pruebas eres el único usuario y tu tabla de pruebas tenga tal vez 3mil registros porque piensas que eso es volumen y ves que todo funciona de maravilla. Y luego una semana después de liberado el sistema se está cayendo a cada rato y nadie sabe por qué se cae los lunes a las 10 AM y resulta que es cuando todo mundo genera el reporte de la semana anterior y hubo mucha actividad y 50 usuarios están jalando 100mil registros a memoria cada uno, asi que ya tienes 5 millones de registros en memoria, además de que la tabla no está indexada y se tarda mucho en obtener los resultados y dos meses después todos leemos la historia de TheDailyWTF.

Imagen de ezamudio

RTFM

O fuckinggoogleit.com

El punto importante

es para mi que a veces hay que llevarse unos golpes para aprender. Odio decir que lo dije ;-) que si se quería algo sencillo y rápido, no se hiciera en Java, sino en Python o alguna otra cosa y dí varias referencias. Pero se decidió hacerlo en Java, para venir a resultar que de todas maneras no hay tiempo de leer el manual, o de probar lo que se sugiere (¿Hibernate.initialize()?)

Creo que es natural cuando uno empieza, las prisas, el ansia por "aprender" y sacar las cosas rápido. Me recuerda la historia del toro y un torito, el toro estaba hasta arriba de un cerro descansandop plácidamente bajo la sombra de un árbol y llega el torito y le dice:

- ¿Ya viste todas esas vacas allá abajo? ¿Qué tal si vamos corriendo y nos "echamos" una vaca cada quien?

A lo que el toro contestó:

- ¿Qué te parece si bajamos caminando tranquilamente y nos "echamos" varias vacas cada quien?

Saludos

Javier Castañón

La historia del toro y el

La historia del toro y el torito es muy buena. Tienes razon ezamudio me quise comer todo el pastel de trancazo y solo me pude comer el merengue. Con calma salen mejor las cosas ademas de que asimilas mejor. Ahorita para la entrega que tengo lo mostrare asi y posteriormente optimizare los procesos para la entrega final. Solo les pido me tengan paciencia y me sigan ayudando tu y javier. Sale pues muchas gracias estamos en contacto.

Hola, donde te puedo

Hola, donde te puedo publicar el codigo de mis archivos con lo que estoy trabajando mi proyecto en hibernate??? aqui en el foro?

Quiero que me enseñes como

Quiero que me enseñes como utilizar el Hibernate.initialize por favor. Hare el servlet filter. No quiero que me pase lo que dice ezamudio y mi sistema se colapse cuando este en produccion. Por favor ayudame.

¡Claro!, aquí en el foro

¡Para eso son las etiquetas HTML permitidas! Observa cómo otro novato hizo una pregunta en el foro de Hibernate:

Ya lo mencioné, publica un pequeño caso de prueba, no cientos de líneas de código, aísla tu problema a su mínima expresión.

No puedo enseñarte

El tiempo que dedico a escribir esto es tiempo que no dedico a algún entretenimiento, a estar con mi familia o hacer un trabajo pagado. Puedo, y me comprometí a, ayudarte a resolver el problema, no a enseñar. Si necesitas respuestas concretas, plantea preguntas concretas: "Ya puse una invocación a Hibernate.initialize() en mi código de la siguiente manera: y ahora me marca la excepción fulana: "

Mira, en los foros de Hibernate, de las preguntas con más de 5 respuestas en los últimos días escogí dos al azar:

¿Por qué escogí de entre las preguntas con más respuestas? Porque una pregunta bien formulada tiene más probabilidades de ser resuelta, aunque puede tomar varias rondas de mensajes, pues no siempre se resuelve a la primera, ni a la segunda. Observa nuestro thread: ¿cuánto código hay? ¡Nada!

Cero y van cuatro: en el código donde te marca el error agrega una invocación a Hibernate.initialize(), si es para inicializar, podrás inferir que la llamada no la realizarás a la mitad de tus invocaciones Hibernate. A falta de código, sigo especulando que esa es la razón de tu problema.

Imagen de ezamudio

falta de sesión

Ese error a mi me suena a que quiso leer una relación de detalle (un to-many pues) sin tener una sesión abierta y truena porque la lista nada más era un placeholder que pone Hibernate, que se resuelve internamente y te da los objetos de la base de datos pero cuando todavía tienes abierta la sesión.

Codigos - JavaBean

 

Codigos - HibernateUtil

 

Codigo - Metodos

import java.util.List;
import org.hibernate.Transaction;
import org.hibernate.Session;
import org.hibernate.Query;

/**
*
* @author Administrador
*/
public class Metodos
{
static int codigoError = 0;
Session session = null;

public Metodos()
{
this.session = HibernateUtil.getSessionFactory().getCurrentSession();
}

/*
Expuse un solo caso de una consulta con la tabla que me estaba dando problemas
*/
public List getServicios()
{
List lista = null;

try
{
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery ("from Servicio");
lista = (List) q.list();
tx.commit();
}
catch (Exception e)
{
e.printStackTrace();
}
return lista;
}
}

Imagen de benek

Puedes encerrar tu código

Puedes encerrar tu código entre etiquetas <code> y </code> para que se vea mucho mejor.

--
Javier Benek

No le entiendo al código

Usa tags. ¿Y en qué línea da el error? ¿El stacktrace?

Metodos

 

Hi!

Hola javier, estos codigos son como me dijo ezamudio que arreglara el problema. Eliminando los archivos .hbm y colocando anotaciones EJB. De esta forma me soluciono el error. El error como ya lo menciono ezamudio se genera cuando quiero leer los datos de las tablas que tienen relacion con la tabla servicios del tipo many-to-one.
 

Asi como me dijo ezamudio ya no me genera la exception: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Pero como dicen las consultas se hace de manera tardia o haragana y eso puede ocasionar un bajo rendimiento de mi aplicacion.

Hi!

Grax, ahora ya se parece mas a un codigo, jejejje.

Imagen de ezamudio

Al contrario

Creo que no has entendido el concepto de la consulta "lazy".

Cuando Hibernate lee datos de una entidad que tiene relación to-many con otra tabla, hay dos opciones: puede traerse de una vez los to-many para cada objeto que pediste, o dejar ahi un arreglo que solamente sirve como placeholder, un marcador para saber que ahí realmente van unos objetos que no se trajo de la base de datos. Este segundo caso, o sea no leer los objetos sino dejar solamente un marcador, es el modo "lazy", porque no lee el detalle en el momento.

La ventaja de lectura "lazy" es que no lees objetos que no te interesan en el momento; pero cuando quieras leer uno, como es tu caso, tiene que estar todavía la sesión de Hibernate abierta, para que el marcador sea reemplazado por una colección de los objetos que realmente van ahí, leidos de la base de datos por Hibernate en el momento en que los pides. Esto es lo que te estaba ocurriendo; querías leer una relación que trajiste de manera "lazy" pero ya no tenías la sesión abierta.

Hay varias maneras de solucionar el problema:
1) usar "lazy=false" en tu configuración, para que se lean de una vez los objetos de la relación to-many y ya no tengas problemas después aunque no haya sesión. Pero esto puede causar problemas en performance.
2) usar el patrón de diseño open session in view para que tengas una sesión de Hibernate abierta mientras generas la página para el usuario y no tengas problemas en resolver cualquier relación "lazy".
3) Implementar en tu DAO métodos para resolver esas relaciones lazy en los objetos que necesitas resolver. Tienes que hacer tu propio código en el DAO para abrir una nueva sesión, refrescar el objeto, leer los detalles y cerrar la sesión.

wow

Ya me quedo mas claro. El problema que yo tenia era que intentaba obtener los datos de la tablas que hacia referencia y ya tenia la session cerrada, la solucion que me indico Javier era tener abierta esta session en lo que durara el requets, pero creo que la solucion que use fue la numero 1, puse mi "lazy = false". Esto me acarrea problemas de performance. Necesito un codigo que use este patron "open session in view" y como generar mi "servlets filter". Me lo podrian mandar a: javadicto@gmail.com

hibernate.cfg.xml

 

Esto es extenuante

"No solicites que te respondan por correo en privado"

Por lo menos no hagan a su correo víctima del email harvesting.

Para terminar con esta agonía:

Al día de hoy 20090518, el primer link es el siguiente:

En la segunda pregunta (contando de arriba hacia abajo) se encuentra el filtro, abundatemente documentado. Con esto doy por terminado mi compromiso en este asunto.

Javier