J'obtiens l'exception suivante:
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)
lorsque j'essaye d'appeler depuis les principales lignes suivantes:
Model subProcessModel = getModelByModelGroup(1112);
System.out.println(subProcessModel.getElement().getNote());
J'ai d'abord implémenté la getModelByModelGroup(int modelgroupid)
méthode comme ceci:
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);
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 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;
}
}
et a obtenu l'exception. Puis un ami m'a suggéré de toujours tester la session et d'obtenir la session en cours pour éviter cette erreur. Alors j'ai fait ceci:
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);
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;
}
}
}
mais toujours, obtenez la même erreur. J'ai beaucoup lu cette erreur et j'ai trouvé des solutions possibles. L'un d'eux était de définir lazyLoad sur false mais je ne suis pas autorisé à le faire, c'est pourquoi on m'a suggéré de contrôler la session
Si vous utilisez Spring marquez la classe comme @Transactional , Spring gérera la gestion de session.
@Transactional public class MyClass { ... }
En utilisant
@Transactional
, de nombreux aspects importants tels que la propagation des transactions sont traités automatiquement. Dans ce cas, si une autre méthode transactionnelle est appelée, la méthode aura la possibilité de rejoindre la transaction en cours en évitant l'exception «pas de session».AVERTISSEMENT Si vous l'utilisez
@Transactional
, soyez conscient du comportement qui en résulte. Consultez cet article pour les pièges courants. Par exemple, les mises à jour des entités sont persistantes même si vous n'appelez pas explicitementsave
la source
@EnableTransactionManagement
à votre configuration pour activer les transactions. " si une autre méthode transactionnelle est appelée, la méthode aura la possibilité de rejoindre la transaction en cours " ce comportement est différent pour les différentes façons dont les transactions sont implémentées, c'est-à-dire le proxy d'interface vs le proxy de classe ou le tissage AspectJ. Reportez-vous à la documentation .Transactional
annotation Spring est donc conseillée, non seulement pour modifier les transactions, mais aussi pour accéder uniquement à celles-ci?Vous pouvez essayer de définir
<property name="hibernate.enable_lazy_load_no_trans">true</property>
dans hibernate.cfg.xml ou persistence.xml
Le problème à garder à l'esprit avec cette propriété est bien expliqué ici
la source
<property name="hibernate.enable_lazy_load_no_trans" value="true"/>
La meilleure façon de gérer le
LazyInitializationException
est d'utiliser laJOIN FETCH
directive:Query query = session.createQuery( "from Model m " + "join fetch m.modelType " + "where modelGroup.id = :modelGroupId" );
Quoi qu'il en soit, n'utilisez PAS les Anti-Patterns suivants comme suggéré par certaines des réponses:
hibernate.enable_lazy_load_no_trans
Parfois, une projection DTO est un meilleur choix que la récupération d'entités, et de cette façon, vous n'en aurez pas
LazyInitializationException
.la source
FetchType=EAGER
, mais ce n'est pas la bonne solution, non?@Transactional
service.J'obtenais la même erreur pour une relation un à plusieurs pour l'annotation ci-dessous.
@OneToMany(mappedBy="department", cascade = CascadeType.ALL)
Modifié comme ci-dessous après avoir ajouté fetch = FetchType.EAGER, cela a fonctionné pour moi.
@OneToMany(mappedBy="department", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
la source
si vous utilisez spring data jpa, spring boot, vous pouvez ajouter cette ligne dans application.properties
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
la source
Cette exception en raison du moment où vous appelez
session.getEntityById()
, la session sera fermée. Vous devez donc rattacher l'entité à la session. Ou la solution facile est simplement configuréedefault-lazy="false"
à votreentity.hbm.xml
ou si vous utilisez des annotations, ajoutez simplement@Proxy(lazy=false)
à votre classe d'entité.la source
J'ai rencontré le même problème. Je pense qu'une autre façon de résoudre ce problème est que vous pouvez modifier la requête pour rejoindre récupérer votre élément à partir du modèle comme suit:
Query query = session.createQuery("from Model m join fetch m.element where modelGroup.id = :modelGroupId")
la source
Cela signifie que l'objet auquel vous essayez d'accéder n'est pas chargé, alors écrivez une requête qui effectue une extraction par jointure de l'objet auquel vous essayez d'accéder.
Par exemple:
Si vous essayez d'obtenir ObjectB à partir d'ObjectA où ObjectB est une clé étrangère dans ObjectA.
Requete :
la source
Il y a plusieurs bonnes réponses ici qui gèrent cette erreur dans une large portée. J'ai rencontré une situation spécifique avec Spring Security qui avait une solution rapide, mais probablement pas optimale.
Pendant l'autorisation de l'utilisateur (immédiatement après la connexion et le passage de l'authentification), je testais une entité utilisateur pour une autorité spécifique dans une classe personnalisée qui étend SimpleUrlAuthenticationSuccessHandler.
Mon entité utilisateur implémente UserDetails et a un ensemble de rôles chargés paresseusement qui a jeté l'exception "org.hibernate.LazyInitializationException - n'a pas pu initialiser le proxy - pas de session". Changer cet ensemble de "fetch = FetchType.LAZY" à "fetch = FetchType.EAGER" a résolu ce problème pour moi.
la source
Si vous utilisez JPQL, utilisez JOIN FETCH est le moyen le plus simple: http://www.objectdb.com/java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_
la source
Face à la même exception dans différents cas d'utilisation.
Cas d'utilisation: essayez de lire les données de la base de données avec la projection DTO.
Solution: utilisez la méthode get au lieu de load .
Opération générique
public class HibernateTemplate { public static Object loadObject(Class<?> cls, Serializable s) { Object o = null; Transaction tx = null; try { Session session = HibernateUtil.getSessionFactory().openSession(); tx = session.beginTransaction(); o = session.load(cls, s); /*change load to get*/ tx.commit(); session.close(); } catch (Exception e) { e.printStackTrace(); } return o; }
}
Classe de persistance
public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "Id") private int customerId; @Column(name = "Name") private String customerName; @Column(name = "City") private String city; //constructors , setters and getters }
Interface CustomerDAO
public interface CustomerDAO { public CustomerTO getCustomerById(int cid); }
Classe d'objets de transfert d'entité
public class CustomerTO { private int customerId; private String customerName; private String city; //constructors , setters and getters
}
Classe d'usine
public class DAOFactory { static CustomerDAO customerDAO; static { customerDAO = new HibernateCustomerDAO(); } public static CustomerDAO getCustomerDAO() { return customerDAO; }
}
DAO spécifique à l'entité
public class HibernateCustomerDAO implements CustomerDAO { @Override public CustomerTO getCustomerById(int cid) { Customer cust = (Customer) HibernateTemplate.loadObject(Customer.class, cid); CustomerTO cto = new CustomerTO(cust.getCustomerId(), cust.getCustomerName(), cust.getCity()); return cto; }
}
Récupération des données: classe de test
CustomerDAO cdao = DAOFactory.getCustomerDAO(); CustomerTO c1 = cdao.getCustomerById(2); System.out.println("CustomerName -> " + c1.getCustomerName() + " ,CustomerCity -> " + c1.getCity());
Présenter les données
Requête et sortie générées par Hibernate System
Hibernate: sélectionnez customer0_.Id comme Id1_0_0_, customer0_.City comme City2_0_0_, customer0_.Name comme Name3_0_0_ de CustomerLab31 customer0_ where customer0_.Id =?
CustomerName -> Cody, CustomerCity -> LA
la source
Si vous utilisez
Grail's
Framework, il est simple de résoudre l' exception d'initialisation différée en utilisant unLazy
mot-clé sur un champ spécifique dans la classe de domaine.Par exemple:
class Book { static belongsTo = [author: Author] static mapping = { author lazy: false } }
Trouvez plus d'informations ici
la source
Dans mon cas, un égaré
session.clear()
causait ce problème.la source
Cela signifie que vous utilisez JPA ou hibernate dans votre code et effectuez une opération de modification sur DB sans effectuer la transaction de logique métier. La solution si simple pour cela est de marquer votre morceau de code @Transactional
la source
utilise session.get (*. class, id); mais ne charge pas la fonction
la source
vous pouvez également le résoudre en ajoutant lazy = false dans votre fichier * .hbm.xml ou vous pouvez initier votre objet dans Hibernate.init (Object) lorsque vous obtenez un objet de db
la source
Effectuez les modifications suivantes dans 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>
la source