कैसे तय करें org.hibernate.LazyInitializationException - प्रॉक्सी को प्रारंभ नहीं किया जा सका - कोई सत्र नहीं


188

मुझे निम्न अपवाद मिले:

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)

जब मैं मुख्य लाइनों से कॉल करने का प्रयास करता हूं:

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

मैंने getModelByModelGroup(int modelgroupid)सबसे पहले इस तरीके को लागू किया :

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

और अपवाद मिला। तब एक मित्र ने मुझे सुझाव दिया कि मैं हमेशा सत्र का परीक्षण करूं और इस त्रुटि से बचने के लिए वर्तमान सत्र प्राप्त करूं। तो मैंने ऐसा किया:

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

लेकिन फिर भी, वही त्रुटि प्राप्त करें। मैं इस त्रुटि के लिए बहुत कुछ पढ़ रहा हूं और कुछ संभव समाधान पाया है। उनमें से एक आलसी को झूठे में स्थापित करना था, लेकिन मुझे ऐसा करने की अनुमति नहीं है, इसलिए मुझे सत्र को नियंत्रित करने का सुझाव दिया गया था

जवाबों:


93

यहां क्या गलत है कि जब आप लेनदेन करते हैं तो आपका सत्र प्रबंधन कॉन्फ़िगरेशन बंद सत्र में सेट होता है। जांचें कि क्या आपके पास कुछ ऐसा है:

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

आपके विन्यास में।

इस समस्या को दूर करने के लिए आप सत्र कारखाने के विन्यास को बदल सकते हैं या एक और सत्र खोल सकते हैं और केवल उन आलसी भरी वस्तुओं के लिए पूछ सकते हैं। लेकिन मैं यहाँ क्या सुझाव दूंगा कि इस आलसी संग्रह को GetModelByModelGroup में ही प्रारंभ करें और कॉल करें:

Hibernate.initialize(subProcessModel.getElement());

जब आप अभी भी सक्रिय सत्र में हैं।

और एक आखिरी बात। एक दोस्ताना सलाह। आपके पास अपनी विधि में ऐसा कुछ है:

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

कृपया इस कोड के लिए बस उन मॉडलों को टाइप करें जिनके पास आईडी स्टेटमेंट में 3 के बराबर आईडी स्टेटमेंट है, बस ऊपर की पंक्तियों के कुछ जोड़े।

कुछ और पढ़ना:

सत्र कारखाना विन्यास

बंद सत्र के साथ समस्या


1
धन्यवाद! मैंने अपनी समस्या का समाधान getCurrentSession () के बजाय OpenSession () का उपयोग करके किया, क्योंकि आपने जो मुझे यह सुझाव दिया था, उनमें से एक के रूप में, लेकिन अब मुझे डर है कि क्या ऐसा करना गलत है
डर है

2
नहीं यह शायद ठीक है। लेकिन अपने सत्रों और लेनदेन को पूरी तरह से नियंत्रित करने में सक्षम होने के लिए कुछ और पढ़ें। मूल बातें जानना वास्तव में महत्वपूर्ण है क्योंकि स्प्रिंग, हाइबरनेट जैसी सभी उच्च स्तरीय प्रौद्योगिकियां और बहुत समान अवधारणा पर काम करती हैं।
गोरोनी

179

यदि आप स्प्रिंग का उपयोग कर रहे हैं तो कक्षा को @ वर्णनात्मक के रूप में चिह्नित करें , फिर स्प्रिंग सत्र प्रबंधन को संभाल लेगा।

@Transactional
public class MyClass {
    ...
}

उपयोग करके @Transactional, लेनदेन के प्रचार जैसे कई महत्वपूर्ण पहलुओं को स्वचालित रूप से नियंत्रित किया जाता है। इस मामले में यदि किसी अन्य लेनदेन विधि को विधि कहा जाता है, तो "नो सत्र" अपवाद से बचने के लिए चल रहे लेनदेन में शामिल होने का विकल्प होगा।

चेतावनी यदि आप उपयोग करते हैं @Transactional, तो कृपया परिणामी व्यवहार से अवगत रहें। आम नुकसान के लिए यह लेख देखें । उदाहरण के लिए, संस्थाओं के अपडेट कायम हैं यदि आप स्पष्ट रूप से कॉल नहीं करते हैं , तो भीsave


21
मैं इस उत्तर के महत्व को कम नहीं कर सकता। मैं गंभीरता से पहले इस विकल्प को आजमाने की सलाह दूंगा।
स्पार्कस्पाइडर

6
@EnableTransactionManagementलेन-देन सक्षम करने के लिए यह भी ध्यान दें कि आपको अपने कॉन्फ़िगरेशन में जोड़ना होगा। " यदि किसी अन्य लेनदेन विधि को विधि कहा जाता है, तो चल रहे लेनदेन में शामिल होने का विकल्प होगा " यह व्यवहार अलग-अलग तरीकों से लेनदेन को लागू करने के लिए अलग है, अर्थात इंटरफ़ेस प्रॉक्सी बनाम क्लास प्रॉक्सी या एस्पेक्टेज वीविंग। प्रलेखन का संदर्भ लें ।
एरिक होफ़र

1
क्या हमें यह समझना चाहिए कि स्प्रिंग Transactionalएनोटेशन की सलाह इस प्रकार दी जाती है, न केवल लेनदेन को संशोधित करने के लिए, बल्कि केवल एक्सेस करने के लिए भी?
स्टीफन

8
मैं गंभीरता से केवल परीक्षण के लिए इस एनोटेशन का उपयोग करने की सिफारिश करूंगा। वास्तविक कोड को अलग-अलग कक्षा में लेनदेन के रूप में प्रत्येक विधि को चिह्नित करना चाहिए। जब तक कक्षा में सभी तरीकों को डेटाबेस से लेनदेन के लिए खुले कनेक्शन की आवश्यकता होगी।
m1ld

1
क्या सिर्फ @ ट्रान्सटेनैशनल की बजाय @ ट्रैंसैशनल (रीडऑनली = ट्रू) लगाना सुरक्षित नहीं है?
हमीद

105

आप सेट करने का प्रयास कर सकते हैं

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

hibernate.cfg.xml या हठ में। xml

इस संपत्ति को ध्यान में रखने की समस्या को यहाँ अच्छी तरह से समझाया गया है


8
क्या आप इसका अर्थ भी बता सकते हैं?
मोहित कंवर

2
मैं भी उत्सुक हूँ कि यह क्या करता है। इसने उस समस्या को ठीक किया जो मैं कर रहा था, लेकिन मैं यह समझना चाहूंगा कि क्यों।
हसन

3
दृढ़ता के लिए। xml:<property name="hibernate.enable_lazy_load_no_trans" value="true"/>
ACV



54

LazyInitializationExceptionJOIN FETCHनिर्देशन का उपयोग करने का सबसे अच्छा तरीका है :

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

वैसे भी, कुछ उत्तरों द्वारा सुझाए गए निम्न प्रतिमानों का उपयोग न करें:

कभी-कभी, DTO प्रोजेक्शन संस्थाओं को लाने की तुलना में एक बेहतर विकल्प है, और इस तरह, आपको कोई भी नहीं मिलेगा LazyInitializationException


मैं कैसे पहचान सकता हूं कि किस कॉल में समस्या है? मुझे कॉल को पहचानना कठिन लग रहा है। क्या कोई रास्ता है ? परीक्षण के उद्देश्य के लिए मैंने इस्तेमाल किया FetchType=EAGER, लेकिन यह सही समाधान नहीं है, है ना?
शांताराम तुपे

बस लॉगिंग का उपयोग करें। और ईगर खराब है, हां।
व्लाद मिहालसी

फिर, आपको @Transactionalसेवा छोड़ने से पहले या तो डीटीओ का उपयोग करना चाहिए या सभी संघों को इनिशियलाइज़ करना चाहिए ।
व्लाद मिहालसी

2
हमें सबसे अच्छे उद्यम अभ्यास की वकालत करनी चाहिए, लेकिन जल्दी ठीक करने की नहीं।
17

21

मुझे एनोटेशन के लिए एक से कई रिश्तों के लिए एक ही त्रुटि मिल रही थी।

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

भ्रूण = FetchType.EAGER जोड़ने के बाद नीचे के रूप में परिवर्तित, यह मेरे लिए काम किया।

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

25
हां यह इसे ठीक कर सकता है लेकिन अब आप डेटा के पूरे पेड़ को लोड कर रहे हैं। इससे ज्यादातर मामलों में नकारात्मक प्रदर्शन प्रभाव पड़ेगा
astro8891

13

यदि आप स्प्रिंग डेटा jpa, स्प्रिंग बूट का उपयोग करते हैं, तो आप इस लाइन को application.properties में जोड़ सकते हैं

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

7
यह एक विरोधी पैटर्न के रूप में माना जाता है। vladmihalcea.com/ /
सुदीप भंडारी

9

जब आप कॉल session.getEntityById()करेंगे तो यह अपवाद , सत्र बंद हो जाएगा। तो आपको सत्र को इकाई को फिर से संलग्न करने की आवश्यकता है। या आसान समाधान सिर्फ default-lazy="false" आपके लिए कॉन्फ़िगर किया गया है entity.hbm.xmlया यदि आप एनोटेशन का उपयोग कर रहे हैं तो बस @Proxy(lazy=false)अपने इकाई वर्ग में जोड़ें ।


5

मैंने उसी मुद्दे का सामना किया। मुझे लगता है कि इसे ठीक करने का एक और तरीका यह है कि आप मॉडल से अपने एलिमेंट को शामिल करने के लिए क्वेरी को बदल सकते हैं:

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

4

इसका मतलब यह है कि जिस ऑब्जेक्ट को आप एक्सेस करने का प्रयास कर रहे हैं वह लोड नहीं है, इसलिए एक क्वेरी लिखें जो उस ऑब्जेक्ट का एक सम्मिलित रूप लेती है जिसे आप एक्सेस करने का प्रयास कर रहे हैं।

उदाहरण के लिए:

यदि आप ObjectA से ObjectB प्राप्त करने का प्रयास कर रहे हैं, जहां ObjectB, ObjectA में एक विदेशी कुंजी है।

प्रश्न:

SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB

3

यहां कई अच्छे उत्तर हैं जो इस त्रुटि को व्यापक दायरे में संभालते हैं। मैं स्प्रिंग सुरक्षा के साथ एक विशिष्ट स्थिति में भाग गया जिसमें एक त्वरित था, हालांकि शायद इष्टतम नहीं था, ठीक करें।

उपयोगकर्ता प्राधिकरण के दौरान (प्रमाणीकरण में लॉग इन करने और पास होने के तुरंत बाद) मैं कस्टम क्लास में एक विशिष्ट प्राधिकरण के लिए एक उपयोगकर्ता इकाई का परीक्षण कर रहा था जो कि SimpleUrlAuthenticationSuccessHandler का विस्तार करता है।

मेरी उपयोगकर्ता इकाई UserDetails को लागू करती है और इसमें आलसी लोड रोल्स का एक सेट होता है, जो "org.hibernate.LazyInitializationException" को फेंक देता है - प्रॉक्सी को प्रारंभ नहीं कर सकता - कोई सत्र नहीं "अपवाद। उस सेट को "fetch = FetchType.LAZY" से "fetch = FetchType.EAGER" में बदलना मेरे लिए यह निर्धारित करता है।



2

विभिन्न उपयोग के मामले में एक ही अपवाद का सामना करना पड़ा।

यहां छवि विवरण दर्ज करें

केस का उपयोग करें: डीटीओ प्रोजेक्शन के साथ DB से डेटा पढ़ने की कोशिश करें

समाधान: उपयोग पाने के बजाय विधि लोड

सामान्य ऑपरेशन

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

}

दृढ़ता वर्ग

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 इंटरफ़ेस

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

एंटिटी ट्रांसफर ऑब्जेक्ट क्लास

public class CustomerTO {

private int customerId;

private String customerName;

private String city;

//constructors , setters and getters

}

फैक्टरी वर्ग

public class DAOFactory {

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

public static CustomerDAO getCustomerDAO() {
    return customerDAO;
}

}

इकाई विशिष्ट 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;
}

}

डेटा पुनर्प्राप्त करना: टेस्ट क्लास

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

वर्तमान डेटा

यहां छवि विवरण दर्ज करें

हाइबरनेट सिस्टम द्वारा उत्पन्न क्वेरी और आउटपुट

हाइबरनेट: customer0_.Id को Id1_0_0_, customer0_.City के रूप में City2_0_0_, customer0_.Name के रूप में Name3_0_0_ CustomerLab31 customer0_d_ customer_abd से कहाँ पर भेजें?

ग्राहक नाम -> कोडी, ग्राहकता -> एलए


1

यदि आप Grail'sफ्रेमवर्क का उपयोग कर रहे हैं , तो डोमेन क्लास में विशिष्ट फ़ील्ड पर कीवर्ड का उपयोग करके आलसी इनिशियलाइज़ेशन अपवाद को हल करना सरल है Lazy

उदाहरण के लिए:

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

आगे की जानकारी यहां पाएं


1

मेरे मामले में एक गलत स्थान session.clear()इस समस्या का कारण था।


1

इसका मतलब है कि आप अपने कोड में जेपीए या हाइबरनेट का उपयोग कर रहे हैं और व्यावसायिक तर्क लेनदेन किए बिना डीबी पर संशोधित संचालन कर रहे हैं। तो इस के लिए सरल समाधान कोड @Transactional का अपना टुकड़ा चिह्नित है



-2

आप अपनी * .hbm.xml फ़ाइल में आलसी = गलत जोड़कर भी इसे हल कर सकते हैं या जब आप db से ऑब्जेक्ट प्राप्त करते हैं तो आप Hibernate.init (ऑब्जेक्ट) में अपनी वस्तु को निष्क्रिय कर सकते हैं।


10
आम तौर पर आलसी = झूठ जोड़ना एक अच्छा विचार नहीं है। यही कारण है कि आलसी डिफ़ॉल्ट रूप से सच है
MoienGK

ओपी ने पहले ही स्पष्ट रूप से कहा कि उसे ऐसा करने की अनुमति नहीं है।
जिंजरहेड

-2

सर्वलेट-संदर्भ.एक्सएमएल में निम्नलिखित बदलाव करें

    <beans:property name="hibernateProperties">
        <beans:props>

            <beans:prop key="hibernate.enable_lazy_load_no_trans">true</beans:prop>

        </beans:props>
    </beans:property>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.