java - occurred - hibernate initialize exception
org.hibernate.LazyInitializationException-no se pudo inicializar el proxy-sin sesiĆ³n (14)
Obtengo la siguiente excepción:
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at sei.persistence.wf.entities.Element_$$_jvstc68_47.getNote(Element_$$_jvstc68_47.java)
at JSON_to_XML.createBpmnRepresantation(JSON_to_XML.java:139)
at JSON_to_XML.main(JSON_to_XML.java:84)
cuando intento llamar desde main a las siguientes líneas:
Model subProcessModel = getModelByModelGroup(1112);
System.out.println(subProcessModel.getElement().getNote());
Implementé el getModelByModelGroup(int modelgroupid)
primer lugar como este:
public static Model getModelByModelGroup(int modelGroupId, boolean openTransaction) {
Session session = SessionFactoryHelper.getSessionFactory().getCurrentSession();
Transaction tx = null;
if (openTransaction)
tx = session.getTransaction();
String responseMessage = "";
try {
if (openTransaction)
tx.begin();
Query query = session.createQuery("from Model where modelGroup.id = :modelGroupId");
query.setParameter("modelGroupId", modelGroupId);
@SuppressWarnings("unchecked")
List<Model> modelList = (List<Model>)query.list();
Model model = null;
// Cerco il primo Model che è in esercizio: idwf_model_type = 3
for (Model m : modelList)
if (m.getModelType().getId() == 3) {
model = m;
break;
}
if (model == null) {
Object[] arrModels = modelList.toArray();
if (arrModels.length == 0)
throw new Exception("Non esiste ");
model = (Model)arrModels[0];
}
if (openTransaction)
tx.commit();
return model;
} catch(Exception ex) {
if (openTransaction)
tx.rollback();
ex.printStackTrace();
if (responseMessage.compareTo("") == 0)
responseMessage = "Error" + ex.getMessage();
return null;
}
y obtuve la excepción. Luego, un amigo me sugirió que siempre pruebe la sesión y obtenga la sesión actual para evitar este error. Así que hice esto:
public static Model getModelByModelGroup(int modelGroupId) {
Session session = null;
boolean openSession = session == null;
Transaction tx = null;
if (openSession){
session = SessionFactoryHelper.getSessionFactory().getCurrentSession();
tx = session.getTransaction();
}
String responseMessage = "";
try {
if (openSession)
tx.begin();
Query query = session.createQuery("from Model where modelGroup.id = :modelGroupId");
query.setParameter("modelGroupId", modelGroupId);
@SuppressWarnings("unchecked")
List<Model> modelList = (List<Model>)query.list();
Model model = null;
for (Model m : modelList)
if (m.getModelType().getId() == 3) {
model = m;
break;
}
if (model == null) {
Object[] arrModels = modelList.toArray();
if (arrModels.length == 0)
throw new RuntimeException("Non esiste");
model = (Model)arrModels[0];
if (openSession)
tx.commit();
return model;
} catch(RuntimeException ex) {
if (openSession)
tx.rollback();
ex.printStackTrace();
if (responseMessage.compareTo("") == 0)
responseMessage = "Error" + ex.getMessage();
return null;
}
}
pero aún recibes el mismo error. He estado leyendo mucho por este error y he encontrado algunas soluciones posibles. Uno de ellos fue establecer lazyLoad en falso, pero no estoy autorizado a hacer esto. Por eso me sugirieron que controlara la sesión.
Aquí hay varias buenas respuestas que manejan este error en un amplio alcance. Me encontré con una situación específica con Spring Security que tuvo una solución rápida, aunque probablemente no óptima.
Durante la autorización del usuario (inmediatamente después de iniciar sesión y pasar la autenticación) estaba probando una entidad de usuario para una autoridad específica en una clase personalizada que amplía SimpleUrlAuthenticationSuccessHandler.
Mi entidad de usuario implementa UserDetails y tiene un conjunto de Roles cargados perezosos que lanzó la excepción "org.hibernate.LazyInitializationException - could not initialize proxy - no Session". Al cambiar ese conjunto de "fetch = FetchType.LAZY" a "fetch = FetchType.EAGER" solucioné esto.
Esta excepción se debe a que cuando se llama a session.getEntityById()
, la sesión se cerrará. Entonces necesita volver a conectar la entidad a la sesión. O la solución fácil es simplemente configurar default-lazy="false"
a su entity.hbm.xml
o si está usando anotaciones simplemente agregue @Proxy(lazy=false)
a su clase de entidad.
Esto significa que el objeto al que está intentando acceder no está cargado, por lo tanto, escriba una consulta que haga una búsqueda conjunta del objeto al que está intentando acceder.
P.ej:
Si está intentando obtener ObjectB desde ObjectA donde ObjectB es una clave externa en ObjectA.
Consulta :
SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB
Lo que está mal aquí es que la configuración de gestión de sesión está configurada para cerrar la sesión cuando se confirma la transacción. Verifica si tienes algo como:
<property name="current_session_context_class">thread</property>
en tu configuración
Para superar este problema, puede cambiar la configuración de la fábrica de sesiones o abrir otra sesión y solo preguntar por esos objetos cargados. Pero lo que sugeriría aquí es inicializar esta colección perezosa en getModelByModelGroup y llamar:
Hibernate.initialize(subProcessModel.getElement());
cuando todavía estás en sesión activa.
Y una última cosa Un consejo amistoso. Tienes algo como esto en tu método:
for (Model m : modelList)
if (m.getModelType().getId() == 3) {
model = m;
break;
}
Por favor, insensible a este código simplemente filtre los modelos con id de tipo igual a 3 en la instrucción de consulta solo un par de líneas arriba.
Algo más de lectura:
Me encontré con el mismo problema. Creo que otra forma de solucionar esto es que puedes cambiar la consulta para unir y obtener tu elemento del modelo de la siguiente manera:
Query query = session.createQuery("from Model m join fetch m.element where modelGroup.id = :modelGroupId")
Obtenía el mismo error para una relación de uno a muchos para la anotación siguiente.
@OneToMany(mappedBy="department", cascade = CascadeType.ALL)
Modificado como a continuación después de agregar fetch = FetchType.EAGER, funcionó para mí.
@OneToMany(mappedBy="department", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
Puedes intentar establecer
<property name="hibernate.enable_lazy_load_no_trans">true</property>
en hibernate.cfg.xml o persistence.xml
El problema a tener en cuenta con esta propiedad está bien explicado here
Realice los siguientes cambios en servlet-context.xml
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.enable_lazy_load_no_trans">true</beans:prop>
</beans:props>
</beans:property>
Si está utilizando Grail''s
Framework Grail''s
, es simple resolver la excepción de inicialización lenta mediante el uso de la palabra clave Lazy
en un campo específico en la clase de dominio.
Por ejemplo:
class Book {
static belongsTo = [author: Author]
static mapping = {
author lazy: false
}
}
Encuentre más información here
Si está utilizando JPQL, utilice UNIR FETCH es la manera más fácil: http://www.objectdb.com/java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_
Si usa Spring marque la clase como @Transactional , entonces Spring se encargará de la administración de la sesión.
@Transactional
public class My Class {
...
}
Al usar @Transactional
, muchos aspectos importantes, como la propagación de transacciones, se manejan automáticamente. En este caso, si se llama a otro método transaccional, el método tendrá la opción de unirse a la transacción en curso evitando la excepción "sin sesión".
también podría solucionarlo agregando lazy = false en su archivo * .hbm.xml o puede iniciar su objeto en Hibernate.init (Object) cuando obtiene el objeto de db
usa session.get (*. class, id); pero no carga la función
La mejor forma de manejar LazyInitializationException
es usar la directiva JOIN FETCH
:
Query query = session.createQuery(
"from Model m " +
"join fetch m.modelType " +
"where modelGroup.id = :modelGroupId"
);
De todos modos, NO use los siguientes antipatrones como lo sugieren algunas de las respuestas:
A veces, una proyección de DTO es una mejor opción que buscar entidades, y de esta manera, no obtendrá ninguna LazyInitializationException
.