JPA EntityManager: मर्ज पर () पर क्यों बनी रहती है?


951

EntityManager.merge() नई वस्तुओं को सम्मिलित कर सकते हैं और मौजूदा अपडेट कर सकते हैं।

कोई क्यों उपयोग करना चाहेगा persist()(जो केवल नई वस्तुएं बना सकता है)?


13
techblog.bozho.net/?p=266 संबंधित
Bozho

2
अगर आपको डायग्राम पसंद हैं। इसे देखें: spitballer.blogspot.in/2010/04/…
RBz

जवाबों:


1615

किसी भी तरह से एक इकाई को PersistenceContext में जोड़ा जाएगा, अंतर यह है कि आप इकाई के साथ क्या करते हैं।

Persist एक इकाई उदाहरण लेता है, इसे संदर्भ में जोड़ता है और उस उदाहरण को प्रबंधित करता है (यानी इकाई के लिए भविष्य के अपडेट को ट्रैक किया जाएगा)।

मर्ज उस प्रबंधित उदाहरण को लौटाता है जिसे राज्य में विलय कर दिया गया था। यह कुछ ऐसा है जो PersistenceContext में मौजूद है या आपकी इकाई का एक नया उदाहरण बनाता है। किसी भी स्थिति में, यह राज्य को आपूर्ति की गई इकाई से कॉपी करेगा, और प्रबंधित प्रतिलिपि लौटाएगा। आपके द्वारा पास किया जाने वाला उदाहरण प्रबंधित नहीं किया जाएगा (आपके द्वारा किए गए कोई भी परिवर्तन लेन-देन का हिस्सा नहीं होगा - जब तक कि आप फिर से मर्ज न कहें)। आप उपयोग किए गए रिटर्न इंस्टेंस (प्रबंधित एक) के माध्यम से कर सकते हैं।

शायद एक कोड उदाहरण मदद करेगा।

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)

परिदृश्य 1 और 3 लगभग बराबर हैं, लेकिन कुछ परिस्थितियां हैं जहां आप परिदृश्य 2 का उपयोग करना चाहते हैं।


3
@dma_k: ऐसा लगता है कि आप हाइबरनेट का उपयोग कर रहे हैं। मैं JPA की तुलना में Hibernate से कम परिचित हूं - लेकिन JPA में यदि आप EntityManager.persist () कहते हैं और एक अलग इकाई में पास हो जाते हैं: a) तुरंत एक EntityExistsException प्राप्त करें या b) फ्लश / कमिट समय पर एक और PersexenceException प्राप्त करें। शायद मैं यहाँ सवाल गलत समझा हूँ?
माइक

49
इस उत्तर में सुधार किया जा सकता है यदि यह उन मामलों को भी कवर करता है जहां इकाई का विलय / अनुगमन किया जा रहा है, जो पहले से ही लगातार संदर्भ में मौजूद है (या कम से कम यह स्पष्ट कर दिया है कि यह केवल व्यवहार का वर्णन करता है जब स्थायी / विलय की गई इकाई पहले से मौजूद नहीं है)
हेनरी

2
क्या एक विधि अधिक निष्पादित है? mergeप्रदर्शन के हिट होने से पहले किसी वस्तु की शायद पूरी प्रतिलिपि?
केविन मेरेडिथ

2
आईडी के बारे में क्या? यदि मेरे पास है तो @GeneratedIdक्या मैं इसे परिदृश्य 2 में प्राप्त कर सकता हूं?
रासियो 13

7
माइक: "मर्ज एक नया उदाहरण बनाता है ...": यह हमेशा सच नहीं होता है। यदि EntityManager अपने संदर्भ में पहले से ही प्रबंधित निकाय पाता है तो वह इस उदाहरण (फ़ील्ड्स को अपडेट करने के बाद) वापस करता है। कृपया अपना उत्तर संपादित करें, फिर मैं इसके लिए मतदान करूंगा।
हेरी

181

दृढ़ता और मर्ज दो अलग-अलग उद्देश्यों के लिए हैं (वे सभी विकल्प नहीं हैं)।

(अंतर की जानकारी का विस्तार करने के लिए संपादित)

जारी रहती है:

  • डेटाबेस में एक नया रजिस्टर डालें
  • इकाई प्रबंधक को ऑब्जेक्ट संलग्न करें।

विलय:

  • उसी आईडी के साथ एक संलग्न ऑब्जेक्ट ढूंढें और इसे अपडेट करें।
  • यदि अद्यतन मौजूद है और पहले से जुड़ी हुई वस्तु लौटाता है।
  • यदि मौजूद नहीं है तो डेटाबेस में नया रजिस्टर डालें।

दृढ़ता () दक्षता:

  • यह मर्ज () की तुलना में डेटाबेस में एक नया रजिस्टर डालने के लिए अधिक कुशल हो सकता है।
  • यह मूल वस्तु की नकल नहीं करता है।

दृढ़ता () शब्दार्थ:

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

उदाहरण:

{
    AnyEntity newEntity;
    AnyEntity nonAttachedEntity;
    AnyEntity attachedEntity;

    // Create a new entity and persist it        
    newEntity = new AnyEntity();
    em.persist(newEntity);

    // Save 1 to the database at next flush
    newEntity.setValue(1);

    // Create a new entity with the same Id than the persisted one.
    AnyEntity nonAttachedEntity = new AnyEntity();
    nonAttachedEntity.setId(newEntity.getId());

    // Save 2 to the database at next flush instead of 1!!!
    nonAttachedEntity.setValue(2);
    attachedEntity = em.merge(nonAttachedEntity);

    // This condition returns true
    // merge has found the already attached object (newEntity) and returns it.
    if(attachedEntity==newEntity) {
            System.out.print("They are the same object!");
    }

    // Set 3 to value
    attachedEntity.setValue(3);
    // Really, now both are the same object. Prints 3
    System.out.println(newEntity.getValue());

    // Modify the un attached object has no effect to the entity manager
    // nor to the other objects
    nonAttachedEntity.setValue(42);
}

इस तरह केवल इकाई प्रबंधक में किसी भी रजिस्टर के लिए 1 संलग्न वस्तु मौजूद है।

एक इकाई के लिए मर्ज () एक आईडी के साथ कुछ इस प्रकार है:

AnyEntity myMerge(AnyEntity entityToSave) {
    AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
    if(attached==null) {
            attached = new AnyEntity();
            em.persist(attached);
    }
    BeanUtils.copyProperties(attached, entityToSave);

    return attached;
}

हालाँकि, यदि MySQL मर्ज () से कनेक्ट किया जा सकता है, तो DUPLICATE KEY UPDATE विकल्प के साथ INSERT पर कॉल का उपयोग करते हुए दृढ़ता () का उपयोग किया जा सकता है, JPA एक बहुत ही उच्च स्तरीय प्रोग्रामिंग है और आप यह नहीं मान सकते कि यह हर जगह होने वाला है।


क्या आप एक ऐसे मामले का नाम रख सकते हैं, जहां से प्रतिस्थापित em.persist(x)करना मान्य नहीं है x = em.merge(x)?
एरोन दिगुल्ला

20
जारी () एक EntityExistsException फेंक सकते हैं। यदि आप यह सुनिश्चित करना चाहते हैं कि आपका कोड एक इंसर्ट कर रहा है न कि उस डेटा का अपडेट जिसे आप लगातार इस्तेमाल करते हैं।
जोसेफ पानादेरो

1
merge()यह भी एक फेंक कर सकते हैंEntityExistsException
शॉन

1
@ कोई नहीं क्योंकि यह एक है RuntimeException, लेकिन इसका जवादोक में उल्लेख नहीं है।
मार्टिन

154

यदि आप असाइन किए गए जनरेटर का उपयोग कर रहे हैं, तो हठ के बजाय मर्ज का उपयोग करना अनावश्यक SQL कथन का कारण बन सकता है , इसलिए प्रदर्शन को प्रभावित कर रहा है।

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

यह समझने के लिए कि यह सब कैसे काम करता है, आपको पहले यह पता होना चाहिए कि हाइबरनेट SQL स्टेटमेंट से इकाई स्थिति में डेवलपर की मानसिकता को स्थानांतरित करता है

हाइबरनेट द्वारा एक इकाई को सक्रिय रूप से प्रबंधित करने के बाद, सभी परिवर्तन डेटाबेस में स्वचालित रूप से प्रचारित होने जा रहे हैं।

हाइबरनेट मॉनिटर वर्तमान में संलग्न इकाइयाँ हैं। लेकिन एक इकाई को प्रबंधित करने के लिए, यह सही इकाई स्थिति में होना चाहिए।

जेपीए की स्थिति को बेहतर ढंग से समझने के लिए, आप निम्नलिखित चित्र की कल्पना कर सकते हैं:

जेपीए इकाई राज्य परिवर्तन

या यदि आप हाइबरनेट विशिष्ट API का उपयोग करते हैं:

हाइबरनेट इकाई राज्य परिवर्तन

उपरोक्त आरेखों के अनुसार, एक इकाई निम्नलिखित चार राज्यों में से एक में हो सकती है:

  • नया (क्षणिक)

    एक नई बनाई गई वस्तु जो कभी भी एक हाइबरनेट Session(उर्फ Persistence Context) के साथ संबद्ध नहीं हुई है और किसी भी डेटाबेस तालिका पंक्ति में मैप नहीं की गई है जिसे नई (क्षणिक) स्थिति में माना जाता है।

    बने रहने के लिए हमें या तो स्पष्ट रूप से EntityManager#persistविधि की आवश्यकता होती है या सकर्मक दृढ़ता का उपयोग करना चाहिए।

  • स्थायी (प्रबंधित)

    एक स्थायी इकाई को डेटाबेस तालिका पंक्ति के साथ जोड़ा गया है और इसे वर्तमान में चल रहे परिप्रेक्ष्य द्वारा प्रबंधित किया जा रहा है। ऐसी इकाई में किए गए किसी भी परिवर्तन को डेटाबेस में (सत्र फ्लश-टाइम के दौरान) पहचाना और प्रचारित किया जा रहा है। हाइबरनेट के साथ, हमें अब INSERT / UPDATE / DELETE कथनों को निष्पादित नहीं करना है। हाइबरनेट एक व्यवहारिक लिखने के पीछे काम करने की शैली को नियोजित करता है और वर्तमान Sessionफ्लश-टाइम के दौरान परिवर्तनों को अंतिम अंतिम क्षण में सिंक्रनाइज़ किया जाता है ।

  • जुदा जुदा

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

    एक अलग इकाई को सक्रिय हाइबरनेट सत्र में जोड़ने के लिए, आप निम्नलिखित विकल्पों में से एक चुन सकते हैं:

    • reattaching

      हाइबरनेट (लेकिन जेपीए 2.1 नहीं) सत्र # अद्यतन विधि के माध्यम से रीटेटिंग का समर्थन करता है। एक हाइबरनेट सत्र किसी दिए गए डेटाबेस पंक्ति के लिए केवल एक एंटिटी ऑब्जेक्ट को जोड़ सकता है। ऐसा इसलिए है क्योंकि पर्सेंटेज कॉन्सेप्ट एक इन-मेमोरी कैश (प्रथम स्तर कैश) के रूप में कार्य करता है और केवल एक मान (इकाई) एक दिए गए कुंजी (इकाई प्रकार और डेटाबेस पहचानकर्ता) के साथ जुड़ा हुआ है। एक इकाई को केवल तब ही रिलेटेड किया जा सकता है जब कोई अन्य JVM ऑब्जेक्ट (समान डेटाबेस पंक्ति से मेल खाते हुए) पहले से ही मौजूदा हाइबरनेट सत्र के साथ जुड़ा हुआ हो।

    • विलय

    मर्ज किसी निकाय निकाय स्थिति (स्रोत) की प्रतिलिपि किसी प्रबंधित निकाय आवृत्ति (गंतव्य) पर करने जा रहा है। यदि वर्तमान सत्र में विलय इकाई के समतुल्य नहीं है, तो डेटाबेस से एक प्राप्त किया जाएगा। मर्ज किए गए ऑपरेशन के बाद भी अलग किए गए ऑब्जेक्ट का उदाहरण अलग रखा जाएगा।

  • हटा दिया

    यद्यपि जेपीए मांग करता है कि प्रबंधित इकाइयां केवल हटाने की अनुमति दी जाती हैं, हाइबरनेट भी अलग-अलग संस्थाओं को हटा सकता है (लेकिन केवल एक सत्र # हटाएं विधि कॉल के माध्यम से)। हटाए गए निकाय को केवल हटाने के लिए निर्धारित किया गया है और सत्र डेटाबेस फ्लश-टाइम के दौरान वास्तविक डेटाबेस DELETE स्टेटमेंट निष्पादित किया जाएगा।


क्या आप एक नज़र stackoverflow.com/questions/46214322/… ले सकते हैं ?
15

@gstackoverflow आपको मिला उत्तर सही है। अधिक जानकारी के लिए, इस लेख या मेरी पुस्तक, हाई-परफॉर्मेंस जावा पर्सिस्टेंस देखें
व्लाद मिहालसी

इस प्रकार अनाथर्मोवल = सच के लिए ऑपरेशन ऑर्डर बदलने की कोई संभावना नहीं है?
16

सामान्य स्थिति में ऑपरेशन के आदेश के बारे में आपका लेख। अनाथमेरेवल के
gstackoverflow

1
तथ्य यह है कि इस तरह के एक आरेख के साथ हाइबरनेट की व्याख्या करना असंभव है। आप अलग होने के बाद सत्र को क्यों नहीं रोक सकते? जब आप पहले से ही अस्तित्व में आने वाली संस्था को बचाने की कोशिश करते हैं तो क्या होता है? जब बचाना और बचना आता है तो फ्लश का व्यवहार अलग क्यों होता है? 1000 ऐसे सवाल हैं, जिनका स्पष्ट तर्क किसी के पास नहीं है।
जिंजरबायर

37

मैंने देखा कि जब मैंने उपयोग किया था em.merge, तो मुझे SELECTहर एक के लिए एक बयान मिला INSERT, यहां तक ​​कि जब कोई क्षेत्र नहीं था कि जेपीए मेरे लिए पैदा कर रहा था - प्राथमिक कुंजी क्षेत्र एक यूयूआईडी था जिसे मैंने खुद सेट किया था। मैं स्विच किया em.persist(myEntityObject)और INSERTफिर सिर्फ बयान मिला ।


3
जब से आप आईडी असाइन करते हैं, तब समझ में आता है और जेपीए कंटेनर को यह पता नहीं है कि आपको वह कहाँ से मिला है। एक (छोटा) मौका है कि ऑब्जेक्ट डेटाबेस में पहले से मौजूद है, उदाहरण के लिए एक परिदृश्य में जहां कई एप्लिकेशन एक ही डेटाबेस को लिखते हैं।
आरोन दिगुल्ला

मैंने इसी तरह के मुद्दे का सामना किया है merge()। मेरे पास जटिल दृश्य के साथ PostgreSQL डेटाबेस था : दृश्य कई तालिकाओं से डेटा एकत्र किया गया था (तालिकाओं में समान संरचना लेकिन अलग-अलग नाम थे)। तो जेपीए ने करने की कोशिश की merge(), लेकिन वास्तव में जेपीए ने पहली बार बनाया SELECT(डेटाबेस के कारण सेटिंग्स अलग-अलग तालिकाओं से एक ही प्राथमिक के साथ कई रिकॉर्ड वापस कर सकती है!), फिर जेपीए (हाइबरनेट एक कार्यान्वयन था) विफल: एक ही कुंजी के साथ कई रिकॉर्ड हैं ( org.hibernate.HibernateException: More than one row with the given identifier was found)। मेरे मामले में मेरी persist()मदद की।
flaz14

29

जेपीए विनिर्देश निम्नलिखित के बारे में कहता है persist()

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

अतः उपयोग persist()करना तब उचित होगा जब ऑब्जेक्ट को अलग की गई वस्तु नहीं होना चाहिए । आप कोड को फेंकना पसंद कर सकते हैं PersistenceExceptionताकि यह तेजी से विफल हो जाए।

हालांकि विनिर्देश स्पष्ट नहीं है , एक वस्तु persist()के @GeneratedValue @Idलिए निर्धारित कर सकता है । merge()हालांकि @Idपहले से उत्पन्न एक वस्तु होनी चाहिए ।


5
+1 के लिए " merge()हालांकि @Id पहले से उत्पन्न एक वस्तु होनी चाहिए । " जब भी EntityManager को ऑब्जेक्ट ID के फ़ील्ड के लिए कोई मान नहीं मिलता है, तो उसे DB में जारी (सम्मिलित) किया जाता है।
उमर

जैसा कि मैंने राज्यों पर स्पष्ट नहीं किया था, मैंने इसे पहले नहीं समझा। आशा है कि यह किसी की मदद करता है जैसा कि यह मेरे लिए किया था। docs.jboss.org/hibernate/core/3.6/reference/en-US/html/…
RBz

1
@GeneratedValue का मर्ज () और दृढ़ता के लिए कोई अलग प्रभाव नहीं है ()
संदीपगौड़ा

17

मर्ज के बारे में कुछ और जानकारी जो आपको दृढ़ता से मर्ज का उपयोग करने में मदद करेगी:

मूल इकाई के अलावा किसी प्रबंधित उदाहरण को वापस करना मर्ज प्रक्रिया का एक महत्वपूर्ण हिस्सा है। यदि समान पहचानकर्ता के साथ एक इकाई उदाहरण पहले से ही दृढ़ता के संदर्भ में मौजूद है, तो प्रदाता अपने राज्य को उस इकाई की स्थिति के साथ अधिलेखित कर देगा जिसे विलय किया जा रहा है, लेकिन प्रबंधित संस्करण जो पहले से मौजूद है, उसे ग्राहक को वापस करना होगा ताकि यह हो सके उपयोग किया गया। अगर प्रदाता ने दृढ़ता के संदर्भ में कर्मचारी उदाहरण को अद्यतन नहीं किया, तो उस उदाहरण का कोई भी संदर्भ नए राज्य में विलय होने के साथ असंगत हो जाएगा।

जब किसी नई इकाई पर मर्ज () किया जाता है, तो यह दृढ़ता () संचालन के समान होता है। यह अस्तित्व के संदर्भ में इकाई को जोड़ता है, लेकिन मूल इकाई उदाहरण को जोड़ने के बजाय, यह एक नई प्रतिलिपि बनाता है और इसके बजाय उस आवृत्ति का प्रबंधन करता है। मर्ज () ऑपरेशन द्वारा बनाई गई प्रतिलिपि इस तरह से बनी रहती है जैसे कि उस पर बनी रहती है।

रिश्तों की उपस्थिति में, मर्ज () ऑपरेशन प्रबंधित इकाई को अद्यतन करने का प्रयास करेगा निकाले गए इकाई द्वारा संदर्भित संस्थाओं के प्रबंधित संस्करणों को इंगित करने के लिए। यदि इकाई का किसी ऐसी वस्तु से संबंध है जिसकी कोई निरंतर पहचान नहीं है, तो मर्ज ऑपरेशन का परिणाम अपरिभाषित है। कुछ प्रदाता प्रबंधित प्रतिलिपि को गैर-स्थायी ऑब्जेक्ट को इंगित करने की अनुमति दे सकते हैं, जबकि अन्य तुरंत एक अपवाद फेंक सकते हैं। मर्ज () ऑपरेशन को इन मामलों में वैकल्पिक रूप से कैस्केड किया जा सकता है ताकि अपवाद को रोका जा सके। हम इस खंड में बाद में मर्ज () ऑपरेशन के कैस्केडिंग को कवर करेंगे। यदि किसी निकाय को निकाय में विलय किया जा रहा है, तो अवैध अवैध अपवाद को फेंक दिया जाएगा।

मर्ज ऑपरेशन में आलसी-लोडिंग संबंध एक विशेष मामला है। यदि किसी आलसी-लोडिंग संबंध को निकाले जाने से पहले किसी इकाई पर ट्रिगर नहीं किया गया था, तो उस संबंध को अनदेखा कर दिया जाएगा जब इकाई का विलय हो जाएगा। यदि रिश्ते को प्रबंधित करते समय ट्रिगर किया गया था और फिर इकाई को अलग करने के दौरान शून्य पर सेट किया गया था, तो इकाई के प्रबंधित संस्करण को इसी तरह मर्ज के दौरान रिश्ते को मंजूरी दे दी जाएगी। "

उपरोक्त सभी जानकारी माइक कीथ और मेरिक श्निकारील द्वारा "प्रो जेपीए 2 मास्टरींग द जावा ™ पर्सिस्टेंस एपीआई" से ली गई थी। अध्याय 6. खंड टुकड़ी और विलय। यह पुस्तक वास्तव में लेखकों द्वारा जेपीए को समर्पित एक दूसरी पुस्तक है। इस नई किताब में कई नई जानकारियां हैं, फिर पूर्व की। मैं वास्तव में उन लोगों के लिए इस पुस्तक को पढ़ने के लिए फिर से तैयार हुआ जो जेपीए के साथ गंभीर रूप से शामिल होंगे। मुझे अपना पहला उत्तर पोस्ट करने के लिए खेद है


17

वहाँ के बीच कुछ और मतभेद हैं mergeऔर persist(मैं फिर से उन पहले से ही यहां पोस्ट करके बताना होगा):

डी 1। mergeपारित इकाई को प्रबंधित नहीं करता है, बल्कि एक और उदाहरण देता है जिसे प्रबंधित किया जाता है। persistदूसरी तरफ पारित इकाई को प्रबंधित करेगा:

//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);

//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);

डी 2। यदि आप किसी निकाय को हटाते हैं और फिर इकाई को वापस बनाए रखने का निर्णय लेते हैं, तो आप ऐसा केवल दृढ़ता () के साथ कर सकते हैं, क्योंकि mergeफेंक देंगे IllegalArgumentException

डी 3। यदि आपने अपनी आईडी (जैसे यूयूआईडी का उपयोग करके) मैन्युअल रूप से देखभाल करने का फैसला किया है, तो एक merge ऑपरेशन बाद के SELECTप्रश्नों को ट्रिगर करेगा ताकि उस आईडी के साथ मौजूद संस्थाओं की तलाश की persistजा सके , जबकि उन प्रश्नों की आवश्यकता नहीं हो सकती है।

D4। ऐसे मामले हैं जब आप बस उस कोड पर भरोसा नहीं करते हैं जो आपके कोड को कॉल करता है, और यह सुनिश्चित करने के लिए कि कोई डेटा अपडेट नहीं किया गया है, बल्कि डाला गया है, आपको उपयोग करना होगा persist


8

मुझे अपनी इकाई पर आलसी अपवाद मिल रहे थे क्योंकि मैं एक आलसी लोड संग्रह तक पहुंचने की कोशिश कर रहा था जो सत्र में था।

मैं एक अलग अनुरोध में क्या करूंगा, सत्र से इकाई को पुनः प्राप्त करता हूं और फिर अपने jsp पृष्ठ पर एक संग्रह तक पहुंचने का प्रयास करता हूं जो समस्याग्रस्त था।

इसे समाप्त करने के लिए, मैंने अपने नियंत्रक में एक ही इकाई को अद्यतन किया और इसे अपने जेएसपी को पारित कर दिया, हालांकि मुझे लगता है कि जब मैंने सत्र में फिर से बचाया कि यह भी सुलभ होगा SessionScopeऔर एक नहीं फेंकेगा LazyLoadingException, उदाहरण 2 का एक संशोधन:

निम्नलिखित ने मेरे लिए काम किया है:

// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!

7

मुझे यह स्पष्टीकरण हाइबरनेट डॉक्स के ज्ञानवर्धक से मिला, क्योंकि उनमें उपयोग का मामला है:

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

आमतौर पर मर्ज () का उपयोग निम्नलिखित परिदृश्य में किया जाता है:

  • अनुप्रयोग पहले निकाय प्रबंधक में किसी ऑब्जेक्ट को लोड करता है
  • ऑब्जेक्ट को प्रेजेंटेशन लेयर तक पहुंचाया जाता है
  • कुछ संशोधन वस्तु के लिए किए जाते हैं
  • ऑब्जेक्ट को व्यावसायिक लॉजिक परत पर वापस भेज दिया जाता है
  • एप्लिकेशन दूसरी इकाई प्रबंधक में मर्ज () कॉल करके इन संशोधनों को जारी रखता है

यहाँ मर्ज का सटीक शब्दार्थ है ():

  • यदि एक ही पहचानकर्ता के साथ एक प्रबंधित उदाहरण है जो वर्तमान में दृढ़ता के संदर्भ में जुड़ा हुआ है, तो दिए गए ऑब्जेक्ट की स्थिति को प्रबंधित उदाहरण पर कॉपी करें
  • यदि वर्तमान में दृढ़ता प्रसंग से जुड़ा कोई प्रबंधित उदाहरण नहीं है, तो इसे डेटाबेस से लोड करने का प्रयास करें, या एक नया प्रबंधित उदाहरण बनाएं
  • प्रबंधित उदाहरण वापस आ गया है
  • दिए गए उदाहरण हठ प्रसंग से जुड़े नहीं हैं, यह अलग रहता है और आमतौर पर खारिज कर दिया जाता है

से: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html


6

उत्तरों के माध्यम से जाने से `कैस्केड 'और आईडी जनरेशन के बारे में कुछ विवरण गायब हैं। प्रश्न देखें

इसके अलावा, यह ध्यान देने योग्य है कि आपके पास Cascadeविलय और अनुशीलन के लिए अलग-अलग एनोटेशन हो सकते हैं : Cascade.MERGEऔर Cascade.PERSISTजिनका इस्तेमाल विधि के अनुसार किया जाएगा।

युक्ति आपका मित्र है;)


6

जावा प्लेटफॉर्म पर निर्मित एंटरप्राइज़ अनुप्रयोगों के क्षेत्र में जेपीए निर्विवाद रूप से एक महान सरलीकरण है। एक डेवलपर के रूप में जिसे जे 2 ईई में पुरानी इकाई बीन्स की पेचीदगियों से जूझना पड़ा, मैं जावा ईई विनिर्देशों के बीच जेपीए को शामिल करने को एक बड़ी छलांग के रूप में देखता हूं। हालाँकि, जेपीए के विवरणों में गहराई से जाने के दौरान मुझे ऐसी चीजें मिलती हैं जो इतनी आसान नहीं हैं। इस लेख में मैं EntityManager के मर्ज की तुलना करता हूं और उन तरीकों को जारी रखता हूं जिनके अतिव्यापी व्यवहार के कारण न केवल एक नौसिखिया के लिए भ्रम पैदा हो सकता है। इसके अलावा मैं एक सामान्यीकरण का प्रस्ताव करता हूं जो दोनों तरीकों को एक अधिक सामान्य विधि के विशेष मामलों के रूप में देखता है।

स्थायी इकाइयाँ

मर्ज विधि के विपरीत हठ विधि बहुत सरल और सहज है। दृढ़ता विधि के उपयोग का सबसे सामान्य परिदृश्य निम्नानुसार अभिव्यक्त किया जा सकता है:

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

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

हालांकि, विवरण अधिक विवरण में जाते हैं, हालांकि, उन्हें याद रखना महत्वपूर्ण नहीं है क्योंकि ये विवरण केवल अधिक या कम विदेशी स्थितियों को कवर करते हैं।

संस्थाओं को विलय करना

दृढ़ता की तुलना में, मर्ज के व्यवहार का वर्णन इतना सरल नहीं है। कोई मुख्य परिदृश्य नहीं है, क्योंकि यह जारी रहने की स्थिति में है, और एक प्रोग्रामर को एक सही कोड लिखने के लिए सभी परिदृश्यों को याद रखना चाहिए। मुझे ऐसा लगता है कि जेपीए डिजाइनर कुछ ऐसा तरीका चाहते थे, जिसकी प्राथमिक चिंता अलग-थलग पड़ने वाली संस्थाओं को संभालना होगा (जैसा कि दृढ़ता से बनी विधि जो मुख्य रूप से नव निर्मित संस्थाओं से संबंधित है।) मर्ज विधि का प्रमुख कार्य राज्य को एक से स्थानांतरित करना है। अप्रबंधित इकाई (तर्क के रूप में पारित) दृढ़ता संदर्भ के भीतर अपने प्रबंधित समकक्ष के लिए। हालाँकि, यह कार्य कई परिदृश्यों में विभाजित है, जो समग्र विधि के व्यवहार की समझदारी को खराब करता है।

जेपीए विनिर्देश से पैराग्राफ को दोहराने के बजाय मैंने एक प्रवाह आरेख तैयार किया है जो योजनाबद्ध रूप से मर्ज के व्यवहार को दर्शाता है:

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

तो, मुझे कब उपयोग करना चाहिए और कब विलय करना चाहिए?

दृढ़ रहना

  • आप चाहते हैं कि विधि हमेशा एक नई इकाई बनाए और एक इकाई को कभी अपडेट न करे। अन्यथा, विधि प्राथमिक कुंजी विशिष्टता के उल्लंघन के परिणामस्वरूप एक अपवाद फेंकता है।
  • बैच प्रक्रियाओं, एक राज्यपूर्ण तरीके से संस्थाओं को संभालना (गेटवे पैटर्न देखें)।
  • प्रदर्शन अनुकूलन

मर्ज

  • आप डेटाबेस में किसी इकाई को सम्मिलित या अद्यतन करने की विधि चाहते हैं।
  • आप एक सांख्यिकीय तरीके से संस्थाओं को संभालना चाहते हैं (सेवाओं में डेटा ट्रांसफर ऑब्जेक्ट)
  • आप एक नई इकाई सम्मिलित करना चाहते हैं जिसमें किसी अन्य इकाई का संदर्भ हो सकता है लेकिन अभी तक नहीं बनाया जा सकता है (संबंध को चिह्नित किया जाना चाहिए)। उदाहरण के लिए, एक नई फोटो को या तो एक नए या एक पूर्ववर्ती एल्बम के संदर्भ में सम्मिलित करना।

E के बीच अंतर क्या है और क्या PC में E का प्रबंधित संस्करण है?
जिंजरबायर

5

परिदृश्य X:

टेबल: स्पिटर (एक), टेबल: स्पिटल्स (कई) (स्पिटल्स एक FK: spitter_id के साथ संबंध के मालिक हैं)

इस परिदृश्य के परिणामस्वरूप बचत होती है: स्पिटर और स्पिटल्स दोनों जैसे कि समान स्पिटर के स्वामित्व में हो।

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.addSpittle(spittle3); // <--persist     
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!

परिदृश्य Y:

यह स्पिटर को बचाएगा, 2 स्पिटल्स को बचाएगा, लेकिन वे समान स्पिटर को संदर्भित नहीं करेंगे!

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.save(spittle3); // <--merge!!       
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!

1
स्पिटर एक वस्तु है जिसे ग्रिग वाल्स की पुस्तक "स्प्रिंग इन एक्शन" के तीसरे संस्करण से लिया गया है। स्पिटर्स वे व्यक्ति होते हैं जो कुछ कहते हैं और उनका स्पिटेल वही होता है जो वे वास्तव में कह रहे होते हैं। तो एक स्पिटर के पास कई स्पिटल्स हैं, जिसका मतलब है कि उसके पास स्ट्रिंग्स की एक सूची है।
जॉर्ज पापाथोडोरो

1
आप एक उदाहरण का उपयोग कर सकते हैं जो स्प्रिंग इन एक्शन को पढ़े बिना थोड़ा अधिक पठनीय है ...
wonderb0lt

1
आपको वास्तव में यह जानने की आवश्यकता नहीं है कि शीर्ष पर एक स्पिट या स्पिटर क्या है क्योंकि यह लिखा गया है कि स्पिटर एक टेबल है, स्पिटर एक अन्य टेबल है जो उसका मालिक है .. यह और वह ...
जॉर्ज पापाथोडोरो

3

एक और अवलोकन:

merge()केवल एक ऑटो-जनरेटेड आईडी (पर परीक्षण किया गया ) IDENTITYऔर SEQUENCEइस तरह की आईडी के साथ रिकॉर्ड आपके टेबल में पहले से मौजूद है। उस स्थिति merge()में रिकॉर्ड को अपडेट करने का प्रयास करेंगे। यदि, हालांकि, एक आईडी अनुपस्थित है या किसी भी मौजूदा रिकॉर्ड से मेल नहीं खा रहा है, तो merge()इसे पूरी तरह से अनदेखा कर देगा और एक डीबी को एक नया आवंटित करने के लिए कहेगा। यह कभी-कभी बहुत सारे कीड़े का स्रोत होता है। merge()एक नए रिकॉर्ड के लिए एक आईडी को मजबूर करने के लिए उपयोग न करें ।

persist()दूसरी ओर आपको कभी भी एक आईडी पास नहीं करने देगा। यह तुरंत विफल हो जाएगा। मेरे मामले में, यह है:

इसके कारण: org.hibernate.PersistentObjectException: अलग की गई इकाई बनी रहती है

हाइबरनेट-जेपा जेवाडोक में एक संकेत है:

फेंकता है : javax.persistence.EntityExistsException - यदि इकाई पहले से मौजूद है। (यदि इकाई पहले से मौजूद है, तो जारी रखने के ऑपरेशन को लागू करने पर EntityExistsException को फेंक दिया जा सकता है, या EntityExistsException या किसी अन्य PersistenceException को फ्लश या प्रतिबद्ध समय पर फेंक दिया जा सकता है।)


2
यह आप ऑटो जेनरेट की गई आईडी का उपयोग नहीं कर रहे हैं, आपको अपने नए एंटिटी को मैन्युअल रूप से आईडी देना होगा। persist()शिकायत नहीं करेंगे कि उसके पास एक आईडी है, यह केवल तभी शिकायत करता है जब उसी आईडी के साथ कुछ पहले से ही डेटाबेस में है।
बजे

1

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

चलो मान लें कि आप एक प्राकृतिक कुंजी / पहचानकर्ता का उपयोग कर सकते हैं।

  • डेटा को बनाए रखने की आवश्यकता होती है, लेकिन एक समय में एक रिकॉर्ड मौजूद होता है और एक अपडेट के लिए कॉल किया जाता है। इस मामले में आप एक दृढ़ता की कोशिश कर सकते हैं और अगर यह एक EntityExistsException फेंकता है, तो आप इसे देखते हैं और डेटा को संयोजित करते हैं:

    प्रयास करें {unitManager.persist (निकाय)}

    पकड़ (EntityExistsException अपवाद) {/ * पुनर्प्राप्त और मर्ज * /}

  • स्थायी डेटा को अपडेट करने की आवश्यकता है, लेकिन एक बार में डेटा के लिए अभी तक कोई रिकॉर्ड नहीं है। इस मामले में आप इसे देखते हैं, और अगर कंपनी गायब है तो एक दृढ़ता से काम करें:

    एंटिटी = unitManager.find (की);

    if (एंटिटी == null) {unitManager.persist (एंटिटी); }

    और {/ * मर्ज * /}

यदि आपके पास प्राकृतिक कुंजी / पहचानकर्ता नहीं है, तो आपके पास यह पता लगाने का कठिन समय होगा कि इकाई मौजूद है या नहीं, या इसे कैसे देखना है।

मर्जों से दो तरीकों से निपटा जा सकता है:

  1. यदि परिवर्तन आमतौर पर छोटे होते हैं, तो उन्हें प्रबंधित इकाई में लागू करें।
  2. यदि परिवर्तन आम हैं, तो जारी इकाई से आईडी की प्रतिलिपि बनाएँ, साथ ही अनलेडेड डेटा। फिर पुरानी सामग्री को बदलने के लिए EntityManager :: merge () कॉल करें।

0

persist (इकाई) का उपयोग पूरी तरह से नई संस्थाओं के साथ किया जाना चाहिए, उन्हें DB में जोड़ने के लिए (यदि इकाई पहले से ही DB में मौजूद है तो EntityExistsException throw होगा)।

मर्ज (निकाय) का उपयोग किया जाना चाहिए, यदि इकाई को अलग कर दिया गया था और बदल दिया गया था, तो दृढ़ता के संदर्भ में इकाई को वापस रखा जाए।

संभवतः दृढ़ता से INSERT sql स्टेटमेंट जेनरेट कर रहा है और UPDATE sql स्टेटमेंट को मर्ज कर रहा है (लेकिन मुझे यकीन नहीं है)।


यह गलत है। यदि आप किसी नए ई पर मर्ज (ई) कहते हैं, तो इसे जारी रखा जाना चाहिए।
पेड्रो लामराओ

@ पेड्रोलामारो वारेन.चिंनल
क्रिस्टियन

जेपीए विनिर्देश संस्करण 2.1 से, खंड 3.2.7.1, दूसरी गोली: "यदि X एक नई इकाई उदाहरण है, तो एक नया प्रबंधित निकाय उदाहरण X 'बनाया गया है और X के राज्य को नए प्रबंधित निकाय उदाहरण X' में कॉपी किया गया है।"
पेड्रो लामारो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.