कैसे हल करने के लिए "रोल की एक संग्रह को शुरू करने में विफल करने के लिए असफल" हाइबरनेट अपवाद


363

मुझे यह समस्या है:

org.hibernate.LazyInitializationException: lazily भूमिका के संग्रह को शुरू करने में विफल: mvc3.model.Topic.comments, कोई सत्र या सत्र बंद नहीं हुआ था

यहाँ मॉडल है:

@Entity
@Table(name = "T_TOPIC")
public class Topic {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    @ManyToOne
    @JoinColumn(name="USER_ID")
    private User author;

    @Enumerated(EnumType.STRING)    
    private Tag topicTag;

    private String name;
    private String text;

    @OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
    private Collection<Comment> comments = new LinkedHashSet<Comment>();

    ...

    public Collection<Comment> getComments() {
           return comments;
    }

}

नियंत्रक, जिसे कॉल मॉडल निम्नलिखित की तरह दिखता है:

@Controller
@RequestMapping(value = "/topic")
public class TopicController {

    @Autowired
    private TopicService service;

    private static final Logger logger = LoggerFactory.getLogger(TopicController.class);


    @RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET)
    public ModelAndView details(@PathVariable(value="topicId") int id)
    {

            Topic topicById = service.findTopicByID(id);
            Collection<Comment> commentList = topicById.getComments();

            Hashtable modelData = new Hashtable();
            modelData.put("topic", topicById);
            modelData.put("commentList", commentList);

            return new ModelAndView("/topic/details", modelData);

     }

}

Jsp- पृष्ठ निम्नलिखित दिखता है:

<%@page import="com.epam.mvc3.helpers.Utils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
      <title>View Topic</title>
</head>
<body>

<ul>
<c:forEach items="${commentList}" var="item">
<jsp:useBean id="item" type="mvc3.model.Comment"/>
<li>${item.getText()}</li>

</c:forEach>
</ul>
</body>
</html>

अपवाद दिखाई देता है, जब jsp देखने। सी के साथ लाइन में : forEach लूप

जवाबों:


214

यदि आप जानते हैं कि आप Commentहर बार जब आप Topicअपने क्षेत्र मैपिंग को बदलते हैं, तो आप इसे देखना चाहेंगे comments:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();

संग्रह डिफ़ॉल्ट रूप से आलसी-लोड होते हैं, यदि आप अधिक जानना चाहते हैं तो इस पर एक नज़र डालें ।


35
क्षमा करें, लेकिन मैं आलसी-लोड का उपयोग करना चाहूंगा। इसलिए, मैंने 'LinkedHashSet' प्रकार को 'PersistentList' में बदल दिया है। अपवाद अभी भी होता है
यूजीन

242
यह एक समाधान के रूप में इस्तेमाल किया जा सकता है, लेकिन समस्या का वास्तविक समाधान नहीं है। अगर हमें आलस लाने की जरूरत है तो क्या होगा?
11

14
लेकिन अगर हम आलसी चाहते हैं तो यह समाधान काम नहीं करेगा और ज्यादातर मामले हम आलसी ही चाहते हैं।
प्रशान्त ठाकरे

103
यह एक प्रकार का उत्तर है जो स्टैक ओवरफ्लो पर हर जगह पॉप अप करता है। इस बिंदु पर लघु, समस्या को हल करता है और MISLEADING होता है। भविष्य के पाठकों के लिए, अपने आप को एक एहसान करो और सीखो कि वास्तव में आलसी और उत्सुकता से लदे हुए हैं, और परिणामों को समझते हैं।
सिड

13
@darrengorman जब मैंने JPA शुरू किया तो मैंने ओपी की तर्ज पर एक प्रश्न पोस्ट किया। मुझे वही प्रतिक्रिया मिली जो आपने दी थी। जल्द ही जब मैंने सैकड़ों हजारों पंक्ति के साथ कुछ परीक्षण किया, तो अनुमान लगाओ कि क्या हुआ? मुझे लगता है कि यह भ्रामक है क्योंकि यह एक समस्या के लिए बहुत आसान उत्तर प्रदान करता है जो ज्यादातर शुरुआती का सामना करेंगे और जल्द ही वे अपने पूरे डेटाबेस को मेमोरी में लोड करेंगे यदि वे सावधान नहीं हैं (और वे नहीं करेंगे, क्योंकि वे नहीं करेंगे इसके बारे में पता होना) :)।
Ced

182

मेरे अनुभव से, मेरे पास प्रसिद्ध LazyInitializationException को हल करने के लिए निम्नलिखित विधियाँ हैं:

(1) Hibernate.initialize का उपयोग करें

Hibernate.initialize(topics.getComments());

(2) JOIN FETCH का प्रयोग करें

आप बच्चे के संग्रह को स्पष्ट रूप से लाने के लिए अपने JPQL में JOIN FETCH सिंटैक्स का उपयोग कर सकते हैं। यह कुछ ऐसा है जैसे ईएजीआर लाने के लिए।

(3) OpenSessionInViewFilter का उपयोग करें

LazyInitializationException अक्सर दृश्य परत में होती है। यदि आप स्प्रिंग फ्रेमवर्क का उपयोग करते हैं, तो आप OpenSessionInViewFilter का उपयोग कर सकते हैं। हालाँकि, मैं आपको ऐसा करने का सुझाव नहीं देता। यह सही ढंग से उपयोग नहीं करने पर प्रदर्शन समस्या की ओर ले जा सकता है।


5
(1) मेरे लिए पूरी तरह से काम किया। मेरा मामला: Hibernate.initialize (रजिस्ट्री.getVehicle ()। GetOwner ()। GetPerson ()। GetAddress ());
लियोनेल सांचे दा सिल्वा

6
ऐसा लगता है कि Hibernate.initialize, EntityManager
marionmaiden

8
यह सही उत्तर होना चाहिए। काम पर मेरी परियोजना में उदाहरण के लिए हम स्पष्ट रूप से EAGER लाने का उपयोग करने वाले नहीं हैं। यह इस विशेष प्रणाली में समस्याओं का कारण बनता है।
स्टीव वाटर्स

आकर्षक लगता है, लेकिन एक और मामले में लागू करने के लिए प्रलेखन की कमी है ... क्या आप कृपया इस समाधान को लागू करने के बारे में कुछ और लिंक या स्पष्टीकरण प्रदान कर सकते हैं?
पिपो

58

मुझे पता है कि यह एक पुराना सवाल है, लेकिन मैं मदद करना चाहता हूं। आप जिस सेवा विधि की जरूरत है, उस पर लेन-देन का एनोटेशन डाल सकते हैं, इस मामले में findTopicByID (id) होनी चाहिए

@Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)

इस एनोटेशन के बारे में अधिक जानकारी मिल सकती है यहां है

अन्य समाधानों के बारे में:

fetch = FetchType.EAGER 

एक अच्छा अभ्यास नहीं है, यदि आवश्यक हो तो इसका उपयोग केवल किया जाना चाहिए।

Hibernate.initialize(topics.getComments());

हाइबरनेट आरंभक आपकी कक्षाओं को हाइबरनेट तकनीक से बांधता है। यदि आप लचीले होने का लक्ष्य बना रहे हैं तो जाने का अच्छा तरीका नहीं है।

आशा है ये मदद करेगा


3
@Transactional एनोटेशन ने मेरे लिए काम किया, लेकिन ध्यान दें कि Propagation.REQUIRED डिफ़ॉल्ट है, कम से कम स्प्रिंग बूट 1.4.2 (स्प्रिंग 4.3) में।
ben3000

4
हाँ, यह है, लेकिन मुझे लगा कि यह स्पष्ट करने के लिए सराहना की जा सकती है कि आप वास्तव में प्रचार परम को बदल सकते हैं
सरबुलोपेक्स

नहीं है @Transactionalएक वसंत-केवल एक चीज है?
कैंपा

@ कांपा हां यह है। यदि आप इसे मैन्युअल रूप से संभालना चाहते हैं, तो आपको अपना व्यवसाय तर्क इकाई प्रबंधक से पुनर्प्राप्त लेन-देन के अंदर रखना चाहिए
sarbuLopex

54

आपकी समस्या का मूल:

डिफ़ॉल्ट रूप से हाइबरनेट से संग्रह (रिश्तों) पर आलसी लोड होता है, जिसका अर्थ है कि जब भी collectionआप अपने कोड में उपयोग करते हैं (यहां कक्षा commentsमें क्षेत्र में Topic) तो हाइबरनेट को डेटाबेस से प्राप्त होता है, अब समस्या यह है कि आपको अपने नियंत्रक में संग्रह मिल रहा है (जहां जेपीए सत्र) बंद हो गया है) यह कोड की वह रेखा है जो अपवाद का कारण बनती है (जहां आप commentsसंग्रह लोड कर रहे हैं ):

    Collection<Comment> commentList = topicById.getComments();

आपको अपने कंट्रोलर (जहां JPA sessionसमाप्त हो गया है) में "टिप्पणियाँ" संग्रह (topic.getComments ()) मिल रहा है और जो अपवाद का कारण बनता है। इसके अलावा अगर आपको commentsअपनी jsp फाइल में इस तरह से कलेक्शन मिला है (बजाय इसे अपने कंट्रोलर में पाने के):

<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>

आप अभी भी उसी कारण के लिए एक ही अपवाद होगा।

समस्या का समाधान:

चूँकि आपके पास FetchType.Eagerइकाई वर्ग में (उत्सुकता से संग्रहित) संग्रह के साथ केवल दो संग्रह हो सकते हैं और क्योंकि आलसी लोडिंग उत्सुकता से लोड करने की तुलना में अधिक कुशल है, मुझे लगता है कि आपकी समस्या को हल करने का यह तरीका सिर्फ FetchTypeउत्सुकता में बदलने से बेहतर है :

यदि आप संग्रह को आलसी बनाना चाहते हैं, और यह काम करना चाहते हैं, तो कोड के इस स्निपेट को अपने साथ जोड़ना बेहतर होगा web.xml:

<filter>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

यह कोड क्या करता है कि यह आपकी लंबाई बढ़ाएगा JPA sessionया जैसा कि दस्तावेज़ कहता है, इसका उपयोग किया जाता "to allow for lazy loading in web views despite the original transactions already being completed."है, इस तरह से JPA सत्र थोड़ा लंबा खुला रहेगा और इस वजह से आप अपनी jsp फ़ाइलों और नियंत्रक कक्षाओं में संग्रह लोड कर सकते हैं ।


7
जेपीएस सत्र क्यों बंद है? इसे कैसे बंद किया जाए? आलसी संग्रह कैसे करें?
डेम्स

1
क्या दो FetchType.Eager संग्रह प्रति इकाई की सीमा को परिभाषित करता है?
क्रिसिनमटाउन

स्प्रिंग बूट में, आप 'application.properties' में 'spring.jpa.open-in-view = true' जोड़ सकते हैं
Askar

28

कारण यह है कि जब आप आलसी लोड का उपयोग करते हैं, तो सत्र बंद हो जाता है।

दो उपाय हैं।

  1. आलसी लोड का उपयोग न करें।

    lazy=falseXML में सेट करें या @OneToMany(fetch = FetchType.EAGER)एनोटेशन में सेट करें ।

  2. आलसी लोड का उपयोग करें।

    सेट lazy=trueएक्सएमएल या सेट में@OneToMany(fetch = FetchType.LAZY)एनोटेशन में ।

    और OpenSessionInViewFilter filterअपने में जोड़ेंweb.xml

विस्तार से मेरी देखें पोस्ट


1
... और फिर भी दोनों समाधान अच्छे नहीं हैं। ईएजीईआर का उपयोग करके सुझाव बड़ी समस्याएं पैदा कर सकते हैं। OpenSessionInViewFilter का उपयोग करना एक विरोधी पैटर्न है।
राफेल

27
@Controller
@RequestMapping(value = "/topic")
@Transactional

मैं जोड़कर इस समस्या को हल करता हूं @Transactional, मुझे लगता है कि इससे सत्र खुला हो सकता है


इसे माइनस वोट क्यों मिला? ऑपरेशन में एक लेन-देन जोड़ना सत्र का विस्तार करता है
ट्यूडर ग्रिगोरियु

1
यह नियंत्रक के लिए विज्ञापन के लिए बुरा व्यवहार है।
राफेल

@ राफेल यह एक बुरा अभ्यास क्यों है?
अमर ऐलाफी

@ArrEllafy -> यहाँ यह एक अच्छी व्याख्या है: stackoverflow.com/a/18498834/1261162
राफेल

22

समस्या हाइबरनेट सत्र बंद होने के साथ एक विशेषता तक पहुँचने के कारण होती है। आपके पास नियंत्रक में हाइबरनेट लेनदेन नहीं है।

संभव समाधान:

  1. यह सब लॉजिक, सर्विस लेयर में , (@ ट्रांसट्रैशनल के साथ) करें, कंट्रोलर में नहीं। ऐसा करने के लिए सही जगह होनी चाहिए, यह एप्लिकेशन के तर्क का हिस्सा है, नियंत्रक में नहीं (इस मामले में, मॉडल को लोड करने के लिए एक इंटरफ़ेस)। सर्विस लेयर के सभी ऑपरेशन ट्रांसेक्शनल होने चाहिए। अर्थात: इस लाइन को TopicService.findTopicByID विधि पर ले जाएँ:

    संग्रह टिप्पणीकार = topicById.getComments ();

  2. 'आलसी' के बजाय 'उत्सुक' का उपयोग करें । अब आप 'आलसी' का उपयोग नहीं कर रहे हैं .. यह एक वास्तविक समाधान नहीं है, यदि आप आलसी का उपयोग करना चाहते हैं, तो अस्थायी (बहुत अस्थायी) वर्कअराउंड की तरह काम करता है।

  3. नियंत्रक में @Transactional का उपयोग करें । इसका उपयोग यहां नहीं किया जाना चाहिए, आप प्रस्तुति के साथ सेवा परत को मिला रहे हैं, यह एक अच्छा डिजाइन नहीं है।
  4. OpenSessionInViewFilter का उपयोग करें , रिपोर्ट किए गए कई नुकसान, संभव अस्थिरता।

सामान्य तौर पर, सबसे अच्छा समाधान 1 है।



आपको यह सूचित करना चाहिए कि सबसे अच्छा समाधान 1 है ... वास्तव में केवल अच्छा समाधान है क्योंकि अन्य सभी पैटर्न विरोधी हैं!
राफेल

19

किसी संग्रह को आलसी लोड करने के लिए एक सक्रिय सत्र होना चाहिए। एक वेब ऐप में ऐसा करने के दो तरीके हैं। आप ओपन सत्र इन व्यू पैटर्न का उपयोग कर सकते हैं , जहां आप अनुरोध की शुरुआत में सत्र खोलने के लिए इंटरसेप्टर का उपयोग करते हैं और इसे अंत में बंद कर देते हैं। वहाँ जोखिम यह है कि आपके पास ठोस अपवाद हैंडलिंग है या आप अपने सभी सत्रों को बांध सकते हैं और आपका ऐप लटका सकता है।

इसे संभालने का दूसरा तरीका यह है कि आपको अपने कंट्रोलर में जितने भी डेटा की जरूरत है, उसे इकट्ठा करके अपना सेशन बंद कर दें और फिर डेटा को अपने मॉडल में भर दें। मैं व्यक्तिगत रूप से इस दृष्टिकोण को पसंद करता हूं, क्योंकि यह एमवीसी पैटर्न की भावना के करीब है। इसके अलावा अगर आपको डेटाबेस से कोई त्रुटि मिलती है तो आप इसे बेहतर तरीके से संभाल सकते हैं यदि यह आपके विचार रेंडरर में होता है। इस परिदृश्य में आपका मित्र है Hibernate.initialize (myTopic.getComments ())। आपको सत्र के लिए ऑब्जेक्ट को फिर से लिखना होगा, क्योंकि आप हर अनुरोध के साथ एक नया लेनदेन बना रहे हैं। उसके लिए session.lock (myTopic, LockMode.NONE) का उपयोग करें।


15

जैसा कि मैंने इस लेख में बताया, इसे संभालने का सबसे अच्छा तरीका है कि LazyInitializationExceptionइसे क्वेरी समय पर लाया जाए, इस तरह:

select t
from Topic t
left join fetch t.comments

आपको हमेशा विरोधी प्रतिमानों से बचना चाहिए:

इसलिए, सुनिश्चित करें कि आपके FetchType.LAZYसंघों को क्वेरी समय पर या मूल संग्रह के भीतर माध्यमिक संग्रह के लिए @Transactionalउपयोग Hibernate.initializeकिया जाता है।


1
व्लाद क्या आपके पास स्प्रिंग-जनित रिपॉजिटरी के फ़ाइनलीबायड () पद्धति द्वारा लाए गए निकाय में एक आलसी-आरंभिक संग्रह के साथ काम करने के लिए कोई सुझाव है? मैं क्वेरी नहीं लिख रहा हूं और लेनदेन मेरे कोड के बाहर है।
क्रिसिनटाउन

की जाँच करें इस लेख आलसी संग्रह आरंभ के बारे में अधिक जानकारी के लिए।
व्लाद मिहालसी

क्या आप यह स्पष्ट कर सकते हैं कि मूल @Transactional दायरे में 'आपके द्वारा' का क्या अर्थ है यह मेरे लिए अस्पष्ट है क्योंकि मुझे यह त्रुटि एक खुले सत्र (जबकि सही नहीं?) में मिल रही है
मिनट के लिए मिचेल हैस्मै

इस दायरे के अंदर, शीर्ष-सबसे लेन-देन सेवा पद्धति, जिसे लेन-देन गेटवे भी कहा जाता है। की जाँच करें TrassctionInterceptorस्टैक ट्रेस में और है कि एक है।
व्लाद मिहेल्सिया

अब तक के सर्वश्रेष्ठ उत्तरों में से एक ... इसे सही के रूप में चिह्नित किया जाना चाहिए। BTW ... यह मानते हुए कि OSIV एक एंटी-पैटर्न है, यह कैसे संभव है जो स्प्रिंग-बूट हाल के संस्करणों पर डिफ़ॉल्ट रूप से सक्षम है? ... शायद यह बुरा नहीं है?
राफेल

10

यदि आप एक इकाई और एक संग्रह या जावा वस्तुओं की सूची (उदाहरण के लिए लंबे प्रकार) के बीच एक संबंध बनाने की कोशिश कर रहे हैं, तो यह कुछ इस तरह होगा:

@ElementCollection(fetch = FetchType.EAGER)
    public List<Long> ids;

1
कई मामलों में, आप वास्तव में ऐसा नहीं करना चाहते हैं। आप यहाँ आलसी लोडिंग के सभी लाभों को ढीला करते हैं
kiedysktos

EAGER का उपयोग करना एक पेशेवर समाधान नहीं है।
राफेल

9

सबसे अच्छा समाधानों में से एक आपके एप्लिकेशन में निम्नलिखित को जोड़ना है। फाइल फ़ाइल: spring.jpa.properties.hibernate.enable_lazy_load_no_trans = true


1
क्या आप ओपी को बता सकते हैं कि वह वास्तव में क्या करता है, कोई भी दुष्प्रभाव, प्रदर्शन प्रभाव?
पीएस

3
आलसी लोडिंग के पीछे, एक नया सत्र हर बार फोड़ा जाता है जब एक एसोसिएशन को आलसी लोड किया जाता है, इसलिए अधिक कनेक्शन कांटे होते हैं और कनेक्शन पूल पर थोड़ा दबाव बनाता है। यदि आपके पास कनेक्शन की संख्या की सीमा है, तो यह संपत्ति उपयोग करने के लिए सही नहीं हो सकती है।
श्रीकत्ता

2
कुछ के लिए, यह एक विरोधी पैटर्न vladmihalcea.com/ के
उड़ी लोया

7

मुझे पता चला है कि घोषित करने @PersistenceContextके रूप में EXTENDEDभी इस समस्या का हल:

@PersistenceContext(type = PersistenceContextType.EXTENDED)

1
नमस्ते, ऐसे बदलावों से सावधान रहें। संचरित हठ प्रसंग संदर्भ निर्माण आलसी है, जो ओपी का इरादा था। तो सवाल यह है कि क्या आप स्टेटलेस होना चाहते हैं या नहीं। यह सेटिंग सिस्टम के उद्देश्य पर निर्भर है और इसे बहुत अधिक नहीं बदलना चाहिए ... उत्सुकता से। क्या आपको पता है मेरा क्या मतलब है। यहाँ पढ़ें stackoverflow.com/questions/2547817/…
kiedysktos

खतरनाक। यह सही उत्तर नहीं है। बहुत अधिक सटीक और सुरक्षित ऊपर अन्य हैं।
राफेल

5

यह वह समस्या थी जिसका मैंने हाल ही में सामना किया था जिसका उपयोग करके मैंने हल किया

<f:attribute name="collectionType" value="java.util.ArrayList" />

यहाँ और अधिक विस्तृत विवरण और इससे मेरा दिन बच गया।


5

आपकी सूची आलसी लोडिंग है, इसलिए सूची लोड नहीं की गई थी। सूची पर कॉल करने के लिए पर्याप्त नहीं है। सूची को अंकित करने के लिए Hibernate.initialize में उपयोग करें। यदि dosnt काम सूची तत्व पर चलता है और प्रत्येक के लिए Hibernate.initialize कॉल करें। लेन-देन के दायरे से लौटने से पहले यह होना चाहिए। इस पोस्ट को देखो ।
निम्न को खोजें -

Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session 

4

मेरे मामले में समस्या को हल करने के लिए यह लाइन गायब थी

<tx:annotation-driven transaction-manager="myTxManager" />

अनुप्रयोग-संदर्भ फ़ाइल में।

@Transactionalएक पद्धति पर टिप्पणी पर ध्यान नहीं दिया गया था।

आशा है उत्तर किसी की मदद करेगा


4

नियंत्रक पर @Transactional एनोटेशन अनुपलब्ध है

@Controller
@RequestMapping("/")
@Transactional
public class UserController {
}

17
मैं तर्क दूंगा कि लेन-देन प्रबंधन सेवा स्तर से संबंधित है जहां व्यापार तर्क रहता है।
सोबर

लेन-देन एनोटेशन गायब नहीं है। नियंत्रक के पास ऐसी टिप्पणी नहीं होनी चाहिए। वे एनोटेशन सेवा स्तर पर होने चाहिए।
राफेल

4

हाइबरनेट @Transactionalएनोटेशन का उपयोग करके , यदि आपको डेटाबेस से एक वस्तु प्राप्त होती है जिसमें आलसी भ्रूण वाले गुण होते हैं, तो आप बस इन विशेषताओं को इस तरह प्राप्त करके प्राप्त कर सकते हैं:

@Transactional
public void checkTicketSalePresence(UUID ticketUuid, UUID saleUuid) {
        Optional<Ticket> savedTicketOpt = ticketRepository.findById(ticketUuid);
        savedTicketOpt.ifPresent(ticket -> {
            Optional<Sale> saleOpt = ticket.getSales().stream().filter(sale -> sale.getUuid() == saleUuid).findFirst();
            assertThat(saleOpt).isPresent();
        });
}

यहां, एक हाइबरनेट प्रॉक्सी-प्रबंधित लेनदेन में, कॉल ticket.getSales()करने का तथ्य बिक्री को लाने के लिए एक और क्वेरी करता है क्योंकि आपने स्पष्ट रूप से पूछा था।


4

आपके लिए दो चीजें होनी चाहिए fetch = FetchType.LAZY

@Transactional

तथा

Hibernate.initialize(topicById.getComments());

2

मानदंड के साथ काम करने वालों के लिए , मैंने पाया

criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);

मुझे जो भी चाहिए था वो सब किया।

संग्रह के लिए प्रारंभिक फ़िंच मोड प्रदर्शन प्रदान करने के लिए FetchMode.LAZY पर सेट है, लेकिन जब मुझे डेटा की आवश्यकता होती है, तो मैं बस उस पंक्ति को जोड़ता हूं और पूरी तरह से आबादी वाली वस्तुओं का आनंद लेता हूं।


2

मेरे मामले में निम्नलिखित कोड एक समस्या थी:

entityManager.detach(topicById);
topicById.getComments() // exception thrown

क्योंकि यह डेटाबेस से अलग हो गया था और हाइबरनेट को अब उस क्षेत्र से सूची को पुनर्प्राप्त नहीं किया गया था जब इसकी आवश्यकता थी। इसलिए मैंने इसे शुरू करने से पहले शुरू किया:

Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm

1

कारण यह है कि आप सेवा के अंदर सत्र बंद करने के बाद अपने नियंत्रक पर टिप्पणी करने की कोशिश कर रहे हैं।

topicById.getComments();

ऊपर टिप्पणीकार केवल तभी लोड करेगा जब आपका हाइबरनेट सत्र सक्रिय होगा, जो मुझे लगता है कि आपने अपनी सेवा में बंद कर दिया है।

तो, आपको सत्र बंद करने से पहले टिप्पणी सूची प्राप्त करनी होगी।


2
हाँ, इस समस्या को बयान, तुम भी एक जवाब एक में प्रदान करना चाहिए हैAnswer
Sarz

1

यदि आप इसके साथ एनोटेट नहीं करते हैं, तो commentsआपके मॉडल वर्ग में संग्रह Topicआलसी रूप से भरा हुआ है, जो कि डिफ़ॉल्ट व्यवहार हैfetch = FetchType.EAGER विशेष रूप से ।

यह ज्यादातर संभावना है कि आपकी findTopicByIDसेवा एक स्टेटबेर हाइबरनेट सत्र का उपयोग कर रही है। एक स्टेटलेस सेशन में पहले स्तर का कैश नहीं है, यानी कोई दृढ़ता का संदर्भ नहीं है। बाद में जब आप पुनरावृत्त करने की कोशिश करते हैं comments, तो हाइबरनेट एक अपवाद फेंक देगा।

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed

समाधान हो सकता है:

  1. के commentsसाथ एनोटेटfetch = FetchType.EAGER

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)   
    private Collection<Comment> comments = new LinkedHashSet<Comment>();
  2. यदि आप अभी भी टिप्पणियों को आलसी लोड करना चाहते हैं , तो हाइबरनेट के स्टेटफुल सत्रों का उपयोग करें , ताकि आप बाद में मांग पर टिप्पणी प्राप्त कर सकें।


1

मेरे मामले में, मेरे पास मैपिंग बी / डब्ल्यू Aऔर Bपसंद है

A है

@OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
Set<B> bs;

में DAOपरत, विधि के साथ एनोटेट किए जाने की जरूरत @Transactionalहै, तो आप के साथ मानचित्रण एनोटेट नहीं किया है लायें प्रकार - उत्सुक


1

सबसे अच्छा समाधान नहीं है, लेकिन उन लोगों के लिए जो इस LazyInitializationExceptionपर विशेष रूप से सामना कर रहे Serializationहैं। यहां आप आलसी प्रारंभिक गुण और nullउन लोगों के लिए सेटिंग की जाँच करेंगे । उसके लिए नीचे का वर्ग बनाएं

public class RepositoryUtil {
    public static final boolean isCollectionInitialized(Collection<?> collection) {
        if (collection instanceof PersistentCollection)
            return ((PersistentCollection) collection).wasInitialized();
        else 
            return true;
    }   
}

आपके एंटिटी वर्ग के अंदर जो आपको आलसी प्रारंभिक गुण हैं, नीचे दिखाए गए तरीके से जोड़ते हैं। इस विधि के अंदर अपने सभी आलसी लोडिंग गुण जोड़ें।

public void checkLazyIntialzation() {
    if (!RepositoryUtil.isCollectionInitialized(yourlazyproperty)) {
        yourlazyproperty= null;
    }

इस checkLazyIntialzation()विधि को उन सभी स्थानों पर कॉल करें जहां आप डेटा लोड कर रहे हैं।

 YourEntity obj= entityManager.find(YourEntity.class,1L);
  obj.checkLazyIntialzation();

0

हाय सभी देर से पोस्टिंग की उम्मीद है कि यह दूसरों की मदद करता है, इस पोस्ट के लिए @GMK को अग्रिम रूप से धन्यवाद देते हुए Hibernate.initialize (ऑब्जेक्ट)

जब आलसी = "सच्चा"

Set<myObject> set=null;
hibernateSession.open
set=hibernateSession.getMyObjects();
hibernateSession.close();

अब अगर मैं सत्र बंद करने के बाद 'सेट' को एक्सेस करता हूं तो यह अपवाद फेंकता है।

मेरा समाधान:

Set<myObject> set=new HashSet<myObject>();
hibernateSession.open
set.addAll(hibernateSession.getMyObjects());
hibernateSession.close();

अब मैं हाइबरनेट सत्र बंद करने के बाद भी 'सेट' तक पहुंच सकता हूं।


0

फिर भी बात करने का एक और तरीका है, आप आलसी लाने के लिए TransactionTemplate का उपयोग कर सकते हैं । पसंद

Collection<Comment> commentList = this.transactionTemplate.execute
(status -> topicById.getComments());

0

समस्या तब होती है क्योंकि कोड एक आलसी JPA संबंध तक पहुँच रहा है जब डेटाबेस के लिए "कनेक्शन" बंद है ( दृढ़ता) हाइबरनेट / जेपीए के संदर्भ में सही नाम है)।

स्प्रिंग बूट में इसे हल करने का एक सरल तरीका एक सेवा परत को परिभाषित करने और @Transactionalएनोटेशन का उपयोग करना है । एक विधि में यह एनोटेशन एक लेनदेन बनाता है जो रिपॉजिटरी परत में फैलता है और विधि समाप्त होने तक दृढ़ता का संदर्भ खुला रखता है। यदि आप ट्रांसेक्शनल विधि के भीतर संग्रह का उपयोग करते हैं तो हाइबरनेट / जेपीए डेटाबेस से डेटा प्राप्त करेंगे।

आपके मामले में, आपको बस अपने @Transactionalतरीके से एनोटेट करने की ज़रूरत है और संग्रह के भ्रूण को उस विधि findTopicByID(id)में TopicServiceमजबूर करना होगा (उदाहरण के लिए, उसका आकार पूछकर):

    @Transactional(readOnly = true)
    public Topic findTopicById(Long id) {
        Topic topic = TopicRepository.findById(id).orElse(null);
        topic.getComments().size();
        return topic;
    }

0

आलसी आरंभीकरण अपवाद से छुटकारा पाने के लिए आपको आलसी संग्रह के लिए कॉल नहीं करना चाहिए जब आप अलग वस्तु के साथ काम करते हैं।

मेरी राय में, सबसे अच्छा तरीका डीटीओ का उपयोग करना है, न कि इकाई। इस स्थिति में आप स्पष्ट रूप से उन फ़ील्ड्स को सेट कर सकते हैं, जिनका आप उपयोग करना चाहते हैं। हमेशा की तरह यह पर्याप्त है। चिंता करने की ज़रूरत नहीं है कि लोमसन जैसा कुछ ObjectMapper, या hashCodeलोम्बोक द्वारा उत्पन्न आपके तरीकों को संक्षेप में कहेंगे।

कुछ विशिष्ट मामलों के लिए आप @EntityGrpaphएनोटेशन का उपयोग कर सकते हैं , जो आपको अपनी इकाई में eagerहोने पर भी लोड करने की अनुमति देते हैं fetchType=lazy


0

इस आलसी प्रारंभिक मुद्दे के लिए कई समाधान हैं -

1) LAZY से EAGER में एसोसिएशन फ़ॉच प्रकार बदलें लेकिन यह एक अच्छा अभ्यास नहीं है क्योंकि यह प्रदर्शन को ख़राब कर देगा।

2) संबंधित ऑब्जेक्ट पर FetchType.LAZY का उपयोग करें और अपनी सेवा परत विधि में ट्रांजेक्शनल एनोटेशन का भी उपयोग करें, ताकि सत्र खुला रहेगा और जब आप topicById.getComments () को कॉल करेंगे, तो चाइल्ड ऑब्जेक्ट (टिप्पणियां) लोड हो जाएंगी।

3) इसके अलावा, कृपया नियंत्रक परत में इकाई के बजाय डीटीओ ऑब्जेक्ट का उपयोग करने का प्रयास करें। आपके मामले में, सत्र नियंत्रक परत पर बंद है। सेवा परत में इकाई को डीटीओ में बदलने के लिए बेहतर है।


-11

मैंने सेट के बजाय सूची का उपयोग करके हल किया:

private List<Categories> children = new ArrayList<Categories>();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.