web-dev-qa-db-fra.com

org.hibernate.LazyInitializationException - impossible d'initialiser le proxy - pas de session

Je reçois 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)

quand j'essaie d'appeler depuis la ligne principale les lignes suivantes:

Model subProcessModel = getModelByModelGroup(1112);
System.out.println(subProcessModel.getElement().getNote());

J'ai d'abord implémenté la méthode getModelByModelGroup(int modelgroupid) 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);
            @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;        
        }

et a l'exception. Ensuite, un ami m'a suggéré de toujours tester la session et de récupérer la session en cours pour éviter cette erreur. Alors j'ai fait ça:

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

    }

mais obtenez toujours la même erreur. J'ai beaucoup lu pour cette erreur et j'ai trouvé quelques solutions possibles. L'un d'eux consistait à 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

132
Blerta Dhimitri

Ce qui est faux ici, c'est que votre configuration de gestion de session est configurée pour fermer la session lorsque vous validez une transaction. Vérifiez si vous avez quelque chose comme:

<property name="current_session_context_class">thread</property> 

dans votre configuration.

Afin de résoudre ce problème, vous pouvez modifier la configuration de la fabrique de sessions ou ouvrir une autre session en demandant simplement à ces objets chargés paresseux. Mais ce que je suggérerais ici est d’initialiser cette collection paresseuse dans getModelByModelGroup lui-même et d’appeler:

Hibernate.initialize(subProcessModel.getElement());

quand vous êtes encore en session active.

Et une dernière chose. Un conseil amical. Vous avez quelque chose comme ça dans votre méthode:

            for (Model m : modelList)
            if (m.getModelType().getId() == 3) {
                model = m;
                break;
            }

S'il vous plaît, installez ce code pour filtrer les modèles dont le type id est égal à 3 dans l'instruction de requête, juste quelques lignes ci-dessus. 

Un peu plus de lecture:

configuration de la fabrique de sessions

problème avec huis clos

68
goroncy

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é sont bien expliqués ici

96
Wilianto Indrawan

Si vous utilisez Spring, marquez la classe comme @Transactional , Spring se chargera de la gestion de session.

@Transactional
public class My Class {
    ...
}

En utilisant @Transactional, de nombreux aspects importants, tels que la propagation de transaction, sont gérés automatiquement. Dans ce cas, si une autre méthode transactionnelle est appelée, la méthode aura l'option de rejoindre la transaction en cours en évitant l'exception "aucune session".

80
user2601995

La meilleure façon de gérer la LazyInitializationException est d'utiliser la directive JOIN FETCH:

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-motifs suivants comme suggéré par certaines des réponses:

Parfois, une projection DTO est un meilleur choix que d'extraire des entités, et de cette façon, vous n'obtiendrez pas LazyInitializationException.

37
Vlad Mihalcea

Je recevais la même erreur pour une à plusieurs relations pour l'annotation ci-dessous. 

@OneToMany(mappedBy="department", cascade = CascadeType.ALL)

Modifié comme suit après l'ajout de fetch = FetchType.EAGER, cela a fonctionné pour moi.

@OneToMany(mappedBy="department", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
9
Smruti R Tripathy

Cette exception est due à la date de fermeture de la session lorsque vous appelez session.getEntityById(). Vous devez donc reconnecter l'entité à la session. Ou La solution facile consiste simplement à configurer default-lazy="false" avec votre entity.hbm.xml ou, si vous utilisez des annotations, ajoutez simplement @Proxy(lazy=false) à votre classe d'entité.

7
Reddeiah Pidugu

si vous utilisez spring data jpa, vous pouvez ajouter cette ligne dans application.properties

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
5
Shaaban Ebrahim

J'ai rencontré le même problème. Je pense qu’un autre moyen de résoudre ce problème consiste à modifier la requête afin qu’elle se joigne à votre élément, comme suit:

Query query = session.createQuery("from Model m join fetch m.element where modelGroup.id = :modelGroupId")
4
Tony Vu

Il existe plusieurs bonnes réponses ici qui traitent cette erreur dans une large portée. J'ai rencontré une situation spécifique avec Spring Security qui avait un correctif rapide, mais probablement pas optimal.

Pendant l'autorisation de l'utilisateur (immédiatement après la connexion et le passage de l'authentification), je testais une entité d'utilisateur pour une autorité spécifique dans une classe personnalisée qui étend SimpleUrlAuthenticationSuccessHandler.

Mon entité utilisateur implémente UserDetails et possède un ensemble de rôles chargés différemment qui lève l'exception "org.hibernate.LazyInitializationException - impossible d'initialiser le proxy - pas de session". Changer cet ensemble de "fetch = FetchType.LAZY" à "fetch = FetchType.EAGER" a corrigé cela pour moi.

2
Night Owl

Si vous utilisez JPQL, JOIN FETCH est la méthode la plus simple: http://www.objectdb.com/Java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_

1
xihui

Cela signifie que l'objet auquel vous essayez d'accéder n'est pas chargé. Écrivez donc une requête qui crée un join fetch de l'objet auquel vous essayez d'accéder. 

Par exemple:

Si vous essayez d'obtenir ObjectB à partir d'ObjectA, ObjectB est une clé étrangère dans ObjectA.

Requête:

SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB
0
rex roy

Confronté à la même exception dans des cas d'utilisation différents.

enter image description here

Cas d'utilisation: Essayez de lire les données de la base de données avec projection DTO.

Solution: Utilisez la méthode get au lieu de charge .

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'objet 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 à une 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 de données: Classe de test

CustomerDAO cdao = DAOFactory.getCustomerDAO();
CustomerTO c1 = cdao.getCustomerById(2);
System.out.println("CustomerName -> " + c1.getCustomerName() + " ,CustomerCity -> " + c1.getCity());

Données actuelles

enter image description here

Requête et sortie générées par le système Hibernate

Hibernate: sélectionnez customer0_.Id comme Id1_0_0_, customer0_.City comme City2_0_0_, customer0_.Name comme Nom3_0_0_ de CustomerLab31 customer0_ à customer0_.Id =?

CustomerName -> Cody, CustomerCity -> LA

0
Kms

Si vous utilisez Grail's Framework, il est simple de résoudre l'exception d'initialisation lazy à l'aide du mot clé Lazy dans un champ spécifique de la classe de domaine.

Par exemple: 

class Book {
    static belongsTo = [author: Author]
    static mapping = {
        author lazy: false
    }
}

Trouvez des informations supplémentaires ici

0
Zeb

Dans mon cas, un session.clear() égaré causait ce problème. 

0
Ab Sin

Cela signifie que vous utilisez JPA ou hibernate dans votre code et que vous effectuez une opération de modification sur la base de données sans effectuer la transaction de logique métier . La solution la plus simple pour cela est de marquer votre morceau de code

Merci.

0
Aman Goel