2009-07-30 12 views
8

मुझे अब तक यह समस्या है, मैंने वेब और एसओ इन और आउट की खोज की है और अभी तक कोई समाधान नहीं मिला है। मुझे उम्मीद है कि आप उस पर मेरी मदद कर सकते हैं।मैप किए गए (माता-पिता-बच्चे) रिश्ते और कैश समस्या के साथ Hibernate @OneToMany

मैं की तरह दो संस्थाओं के बीच एक माता पिता के बच्चे का रिश्ता है निम्नलिखित:

@Entity 
public class Parent { 
    // ... 

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) 
    private Set<Child> children = new HashSet<Child>(); 

    // ... 
} 

@Entity 
public class Child { 
    // ... 

    @ManyToOne(fetch = FetchType.LAZY) 
    private Parent parent; 

    // ... 
} 

बात है कि जब मैं एक नए बच्चे बना सकते हैं और एक माता पिता के लिए असाइन करें, माता पिता को अद्यतन नहीं हो जाता है जब यह पहले से ही कैश में है।

Parent parent = new Parent(); 
em.persist(parent); 

// ... 

Child child = new Child(); 
child.setParent(parent); 
em.persist(child); 

parent.getChildren().size(); // returns 0 

मैं @PreUpdate उपयोग करने के लिए स्वचालित रूप से माता पिता के लिए बच्चे को जोड़ने के लिए जब बच्चे एक समान होती है की कोशिश की है, लेकिन मामले में हम 2 अलग धागे में 2 इकाई प्रबंधक होते हैं जब (JBoss में की तरह), मुद्दा अभी तक मौजूद है, जब तक हम em.refresh(parent)

तो सवाल यह है कि - समस्या को आसानी से खत्म करने और यह सुनिश्चित करने का कोई तरीका है कि parent.getChildren() हमेशा बच्चों की अद्यतित सूची लौटाएं?

उत्तर

8

अधिकांश ओआरएम इस तरह से व्यवहार करेंगे।

कैश में ऑब्जेक्ट डेटाबेस से अपडेट नहीं किया गया है (एक अतिरिक्त पठन जो आवश्यक नहीं है)। ऑब्जेक्ट मॉडल और दृढ़ता को अलग के रूप में भी सोचें। यानी अपने ऑब्जेक्ट मॉडल को अपने साथ संगत रखें और आपके लिए यह करने के लिए दृढ़ता तंत्र पर भरोसा न करें।

तो यदि आप संग्रह में ऑब्जेक्ट को जोड़ना चाहते हैं तो उसे "सेटपेरेंट" कोड में करें।

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

बाल में setParent बनाने addChild

public void addChild(Child child) { 
    child.setParent0(this); 
    getChildren().add(individualNeed); 
} 

कहा जाता है माता पिता के लिए एक विधि जोड़ें और फिर:

बाल में
public void setParent(Parent parent) { 
    parent.addChild(child); 
} 

setParent0 बच्चे पर माता-पिता के लिए संपत्ति stter है।

public void setParent0(Parent parent) { 
    this.parent = parent; 
} 

मैं भी सुझाव है कि "getChildren" विधि अपरिवर्तनीय संग्रह लौट ताकि डेवलपर्स inadvertantly इस विधि (मैं इस सब में मुश्किल तरीके से सीखा) का उपयोग नहीं नहीं है।

एक और बात, आपको उपरोक्त कोड में शून्य जांच कोड और अन्य रक्षात्मक टुकड़े होना चाहिए, मैंने इसे स्पष्टता के लिए छोड़ दिया।

+0

में पाया जा सकता अपने व्यापक जवाब, माइकल के लिए धन्यवाद। मुझे इसमें कुछ अच्छी जानकारी मिली है। लेकिन, मुझे डर लग रहा है, यह समस्या मेरे पास है समाधान नहीं करता है क्योंकि दो अलग EntityManager उदाहरणों दो अलग-अलग कैश रखें और जब उनमें से एक अद्यतन करता है एक इकाई उदाहरण, एक दूसरे को अपडेट नहीं हुआ है और यह कैश की गई इकाई पुराना हो जाता है है – artemb

+0

लगता है जैसे आपको अपडेट ट्रिगर्स को देखने की आवश्यकता है जो तब उस ऑब्जेक्ट को ले लेंगे और अन्य कैश अपडेट करेंगे। या यदि आप समाधान सुपर क्लस्टरिंग को कैशिंग करते हैं तो आप उसी क्लस्टर के उन दो कैश सदस्यों को बना सकते हैं। –

+0

दुर्भाग्यवश मेरे पास हाइबरनेट के सत्र कैश पर कोई नियंत्रण नहीं है। या मैं है – artemb

1

कैशिंग के साथ आपकी समस्या के संबंध में, यह एक बहुत ही आम समस्या है जब आपके पास अलग-अलग कैश के साथ एक ही डेटाबेस के विरुद्ध कई वीएम चल रहे हैं। इसे "कैश बहाव" कहा जाता है।

अधिकांश हाइबरनेट-अनुकूल कैश कार्यान्वयन (ehcache, OSCache और SwarmCache) में एक वितरित कैश अंतर्निहित है जिसका उपयोग कैश को सिंक्रनाइज़ करने के लिए किया जा सकता है। वितरित कैश, आम तौर पर, कैश की स्थिति को अद्यतन करने वाले मल्टीकास्ट संदेश भेजता है। सत्र Factory.evict (कक्षा, आईडी) द्वारा एक दूसरे स्तर के कैश बेदखल करने के लिए, उदाहरण के लिए, क्लस्टर में अन्य कैशों को एक अमान्य संदेश भेजा जाएगा जो उस ऑब्जेक्ट की अन्य प्रतियों को अन्य कैशों में अमान्य कर देगा।

अपने तैनाती के आधार पर, बहुस्त्र्पीय या नहीं आप के लिए स्वीकार्य हो सकता है हो सकता है। यदि ऐसा नहीं है तो आपको memcached जैसे एकल-कैश समाधान का उपयोग करने की आवश्यकता हो सकती है।

मैं व्यक्तिगत रूप से हाँ कैश का वितरित कैश के विन्यास बहुत स्पष्ट पाया।

एह कैश थोड़ा और विस्तार से यहाँ में समस्या पर चर्चा करता है: http://ehcache.org/documentation/distributed_caching.html

4

सुंदर सुनिश्चित करें कि आपके यहाँ समस्या अपने कास्केड सेटिंग है।

@Entity 
public class Parent { 
    // ... 

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, 
     cascade = {CascadeType.REMOVE, CascadeType.PERSIST}) 
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE}) 
    private Set<Child> children = new HashSet<Child>(); 

    // ... 
} 

@Entity 
public class Child { 
    // ... 

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) 
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE}) 
    private Parent parent; 

    // ... 
} 

इन कैस्केड सेटिंग्स का उपयोग करके बच्चों के ऑब्जेक्ट्स को जारी रखने और अद्यतनों को कैस्केड किया जाएगा।

उदाहरण के लिए। इस पर

Parent parent = new Parent(); 
em.persist(parent); 

// ... 

Child child = new Child(); 
child.setParent(parent); 
em.persist(child); //will cascade update to parent 

parent.getChildren().size(); // returns 1 

या

Parent parent = new Parent(); 
Child child = new Child(); 
parent.setChild(parent); 
em.persist(parent); //will cascade update to child 

child.getParent(); // returns the parent 

अधिक जानकारी Hibernate Annotations

संबंधित मुद्दे