it-swarm.com.de

org.hibernate.LazyInitializationException - Proxy konnte nicht initialisiert werden - keine Sitzung

Ich bekomme die folgende Ausnahme:

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)

wenn ich versuche, von main aus die folgenden leitungen anzurufen:

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

Ich habe die getModelByModelGroup(int modelgroupid) Methode zuerst so implementiert:

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

und bekam die Ausnahme. Dann schlug mir ein Freund vor, die Sitzung immer zu testen und die aktuelle Sitzung abzurufen, um diesen Fehler zu vermeiden. Also habe ich das gemacht:

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

    }

bekomme aber trotzdem den gleichen fehler. Ich habe viel für diesen Fehler gelesen und einige mögliche Lösungen gefunden. Einer von ihnen war, LazyLoad auf false zu setzen, aber ich darf das nicht, deshalb wurde mir vorgeschlagen, die Sitzung zu kontrollieren

132
Blerta Dhimitri

Was hier falsch ist, ist, dass Ihre Sitzungsverwaltungskonfiguration so eingestellt ist, dass die Sitzung geschlossen wird, wenn Sie die Transaktion festschreiben. Prüfen Sie, ob Sie etwas haben:

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

in deiner Konfiguration.

Um dieses Problem zu überwinden, können Sie die Konfiguration der Session Factory ändern oder eine andere Session öffnen und erst danach nach den Lazy-Load-Objekten fragen. Ich würde jedoch vorschlagen, diese Lazy-Collection in getModelByModelGroup selbst zu initialisieren und Folgendes zu nennen:

Hibernate.initialize(subProcessModel.getElement());

wenn Sie sich noch in einer aktiven Sitzung befinden.

Und noch ein letztes. Ein freundlicher Rat. Sie haben so etwas in Ihrer Methode:

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

Bitte installieren Sie diesen Code, indem Sie die Modelle mit der Typ-ID 3 in der Abfrageanweisung nur ein paar Zeilen darüber filtern. 

Noch etwas lesen:

Session Factory Konfiguration

Problem mit geschlossener Sitzung

68
goroncy

Sie können versuchen zu setzen 

<property name="hibernate.enable_lazy_load_no_trans">true</property>

in hibernate.cfg.xml oder persistence.xml

Das Problem, das bei dieser Eigenschaft zu beachten ist, ist gut erklärt hier

96

Wenn Sie die Klasse mit Spring als @Transactional markieren, übernimmt Spring die Sitzungsverwaltung.

@Transactional
public class My Class {
    ...
}

Durch die Verwendung von @Transactional werden viele wichtige Aspekte wie Transaktionsweitergabe automatisch behandelt. Wenn in diesem Fall eine andere Transaktionsmethode aufgerufen wird, hat die Methode die Option, der laufenden Transaktion beizutreten, wobei die Ausnahme "keine Sitzung" vermieden wird.

80
user2601995

Der beste Weg, die LazyInitializationException zu behandeln, ist die JOIN FETCH-Direktive:

Query query = session.createQuery(
    "from Model m " +
    "join fetch m.modelType " +
    "where modelGroup.id = :modelGroupId"
);

Verwenden Sie auf keinen Fall die folgenden Anti-Patterns, wie in einigen Antworten vorgeschlagen:

Manchmal ist eine DTO-Projektion eine bessere Wahl als das Abrufen von Entitäten, und auf diese Weise erhalten Sie keine LazyInitializationException.

37
Vlad Mihalcea

Ich habe den gleichen Fehler für eine zu viele Beziehungen für die unten stehende Anmerkung erhalten. 

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

Nach dem Hinzufügen von fetch = FetchType.EAGER wie folgt geändert, hat es für mich funktioniert.

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

Diese Ausnahme wird beim Aufruf von session.getEntityById() geschlossen, und die Sitzung wird geschlossen. Sie müssen also die Entität erneut an die Sitzung anhängen. Oder Die einfache Lösung ist, default-lazy="false" einfach in Ihren entity.hbm.xml zu konfigurieren, oder wenn Sie Anmerkungen verwenden, fügen Sie @Proxy(lazy=false) Ihrer Entitätsklasse hinzu.

7
Reddeiah Pidugu

wenn Sie Spring Data jpa verwenden, können Sie diese Zeile in application.properties hinzufügen

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

Ich bin auf das gleiche Problem gestoßen. Ich denke, eine andere Möglichkeit, dies zu beheben, besteht darin, dass Sie die Abfrage so ändern können, dass Sie Ihr Element vom Modell abrufen:

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

Es gibt mehrere gute Antworten, die diesen Fehler in einem breiten Umfang behandeln. Ich bin auf eine spezielle Situation mit Spring Security gestoßen, die eine schnelle, wenn auch wahrscheinlich nicht optimale Lösung hatte.

Während der Benutzerautorisierung (unmittelbar nach dem Anmelden und dem Bestehen der Authentifizierung) habe ich eine Benutzerentität für eine bestimmte Berechtigung in einer benutzerdefinierten Klasse getestet, die SimpleUrlAuthenticationSuccessHandler erweitert.

Meine Benutzerentität implementiert UserDetails und verfügt über eine Gruppe von faul geladenen Rollen, die die Ausnahme "org.hibernate.LazyInitializationException - Proxy konnte keine Sitzung initialisieren" ausgelöst hat. Das Ändern dieses Satzes von "fetch = FetchType.LAZY" in "fetch = FetchType.EAGER" hat dies für mich behoben.

2
Night Owl

Wenn Sie JPQL verwenden, ist JOIN FETCH der einfachste Weg: http://www.objectdb.com/Java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_

1
xihui

Das bedeutet, dass das Objekt, auf das Sie zugreifen möchten, nicht geladen ist. Schreiben Sie daher eine Abfrage, die einen Join-Abruf des Objekts abfragt, auf das Sie zugreifen möchten. 

Z.B:

Wenn Sie versuchen, ObjectB von ObjectA abzurufen, wobei ObjectB ein Fremdschlüssel in ObjectA ist.

Abfrage:

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

Konfrontiert die gleiche Ausnahme in verschiedenen Anwendungsfällen.

enter image description here

Anwendungsfall: Versuchen Sie, Daten mit DTO-Projektion aus der Datenbank zu lesen.

Lösung: Verwenden Sie get anstelle von Laden .

Generische Operation

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

}

Persistenzklasse

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

}

CustomerDAO-Schnittstelle

public interface CustomerDAO 
     {
   public CustomerTO getCustomerById(int cid);
     }

Entitätsübertragungsobjektklasse

public class CustomerTO {

private int customerId;

private String customerName;

private String city;

//constructors , setters and getters

}

Fabrikklasse

public class DAOFactory {

static CustomerDAO customerDAO;
static {
    customerDAO = new HibernateCustomerDAO();
}

public static CustomerDAO getCustomerDAO() {
    return customerDAO;
}

}

Mandantenspezifisches DAO

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

}

Daten abrufen: Testklasse

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

Vorhandene Daten

enter image description here

Abfrage und Ausgabe von Hibernate System

Ruhezustand: Wählen Sie customer0_.Id als Id1_0_0_, customer0_.City als City2_0_0_, customer0_.Name als Name3_0_0_ aus CustomerLab31 customer0_, wobei customer0_.Id =?

Kundenname -> Cody, Kundenstadt -> LA

0
Kms

Wenn Sie Grail's Framework verwenden, können Sie einfach die lazy-Initialisierungsausnahme mit dem Schlüssel Lazy für ein bestimmtes Feld in der Domänenklasse auflösen.

Zum Beispiel: 

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

Weitere Informationen hier

0
Zeb

In meinem Fall verursachte eine falsch platzierte session.clear() dieses Problem. 

0
Ab Sin

Dies bedeutet, dass Sie in Ihrem Code JPA oder einen Ruhezustand verwenden und eine Änderungsoperation für die DB durchführen, ohne die Geschäftslogik-Transaktion auszuführen. Dies ist eine einfache Lösung, um Ihren Code @Transactional zu markieren

Vielen Dank.

0
Aman Goel