हाइबरनेट में विभिन्न बचत विधियों के बीच अंतर क्या हैं?


199

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

अब तक मैंने जिन तरीकों की पहचान की है वे हैं:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()

जवाबों:


117

यहाँ तरीकों की मेरी समझ है। मुख्य रूप से ये एपीआई पर आधारित हैं, हालांकि मैं इन सभी का अभ्यास में उपयोग नहीं करता हूं।

saveOrUpdate कॉल कुछ चेक के आधार पर सेव या अपडेट करते हैं। उदाहरण के लिए, यदि कोई पहचानकर्ता मौजूद नहीं है, तो सेव कहा जाता है। अन्यथा अद्यतन कहा जाता है।

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

अद्यतन मौजूदा पहचानकर्ता का उपयोग करके इकाई को बनाए रखने का प्रयास करता है। यदि कोई पहचानकर्ता मौजूद नहीं है, तो मेरा मानना ​​है कि एक अपवाद फेंक दिया गया है।

saveOrUpdateCopy यह पदावनत है और अब इसका उपयोग नहीं किया जाना चाहिए। इसके बजाय वहाँ है ...

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

जारी रखें जैसा कि ऊपर उल्लेख किया गया है, यह क्षणिक वस्तुओं पर उपयोग किया जाता है। यह जनरेट आईडी वापस नहीं करता है।


22
मैं इसे उत्तर के रूप में स्वीकार करना चाहता हूं, लेकिन एक बात अभी भी स्पष्ट नहीं है: चूंकि बचत () अपडेट पर वापस गिरती है (), यदि ऐसी वस्तु मौजूद है, तो व्यवहार में saveOrUpdate () से कैसे भिन्न होता है?
हेनरिक पॉल

यह कहाँ निर्दिष्ट है, कि सेविंग अलग उदाहरणों पर काम करेगा?
9

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

1
नीचे दिए गए जार्डोल्फ द्वारा उत्तर अधिक सटीक है।
एज़ेरोल

2
यह देखते हुए कि हाइबरनेट शायद जानता है कि कोई वस्तु किस स्थिति में है, हमें प्रोग्राम लिखते समय मैन्युअल रूप से ऐसा क्यों करना पड़ता है। बस एक बचत विधि होनी चाहिए।
मास्टरएक्सिलो

116
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
    METHOD                TRANSIENT                      DETACHED            
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                     sets id if doesn't         sets new id even if object   
    save()         exist, persists to db,        already has it, persists    
                  returns attached object     to DB, returns attached object 
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                     sets id on object                    throws             
   persist()       persists object to DB            PersistenceException     
                                                                             
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                                                                             
   update()              Exception                persists and reattaches    
                                                                             
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                copy the state of object in      copy the state of obj in    
    merge()        DB, doesn't attach it,    ║      DB, doesn't attach it,    
                  returns attached object         returns attached object    
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                                                                             
saveOrUpdate()║           as save()                       as update()         
                                                                             
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝

updateएक क्षणिक वस्तु ठीक है, मुझे कोई अपवाद नहीं मिला।
GMsoF

जो मुझे पता है, हम किसी भी तरह से एक क्षणिक को जारी नहीं रख सकते। मुझे लगता है कि अंतर अलग और लगातार हो सकता है। कृप्या मुझे सही करें।
राम

यहां कई त्रुटियां हैं ... उदाहरण के लिए 1) )save () "" संलग्न वस्तु "वापस नहीं करता है, यह ´id´ लौटाता है; 2) )persist () ´ को ´id neither सेट करने की गारंटी नहीं है, न ही यह "DB के लिए ऑब्जेक्ट को बनाए रखता है"; ...
यूजेन लाबुन

67
  • दृढ़ता और बचत के बीच सूक्ष्म अंतर की व्याख्या के लिए हाइबरनेट फोरम देखें । ऐसा लगता है कि अंतर INSERT बयान को अंजाम देने का समय है। चूंकि सेव पहचानकर्ता को वापस कर देता है, इसलिए INSERT स्टेटमेंट को लेनदेन की स्थिति की परवाह किए बिना तुरंत निष्पादित किया जाना चाहिए (जो आमतौर पर एक बुरी बात है)। जारी रहती है वर्तमान में चल रहे लेनदेन के बाहर बस पहचानकर्ता के लिए किसी भी स्टेटमेंट्स को निष्पादित नहीं होंगे। Save / Persist दोनों क्षणिक उदाहरणों पर कार्य करते हैं , अर्थात ऐसे उदाहरण जिन्हें कोई पहचानकर्ता अभी तक सौंपा नहीं गया है और जैसे कि DB में सहेजे नहीं गए हैं।

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


सम्मिलित विवरण तब भी नहीं होता है जब आपके पास अपना स्वयं का आईडी जनरेटर हो
kommradHomer

तो अलग की गई वस्तु के मामले में, मर्ज सेलेक्ट हो जाएगा जबकि अपडेट नहीं होगा?
गाब

1
save() - If an INSERT has to be executed to get the identifier, then this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is problematic in a long-running conversation with an extended Session/persistence context.क्या आप मुझे बता सकते हैं कि एक सत्र के बाहर एक इंसर्ट कैसे हो सकता है और यह खराब क्यों है?
एरान मोराद

अस्वीकरण: मैंने लंबे समय तक हाइबरनेट का उपयोग नहीं किया है। IMO मुद्दा यह है: हस्ताक्षर और बचाने के अनुबंध () की आवश्यकता है कि नई वस्तु के लिए एक पहचानकर्ता रिटर्न को बचाएं। आपके द्वारा चुनी गई आईडी-पीढ़ी की रणनीति के आधार पर, पहचानकर्ता डीबी द्वारा एक मूल्य INSERTएड होने पर उत्पन्न होता है । नतीजतन, उन मामलों में आप किसी पहचानकर्ता को अभी उत्पन्न किए बिना नहीं लौटा सकते हैं और इसे उत्पन्न करने के लिए आपको INSERT अभी चलना होगा । के बाद से, एक लंबे समय से चल लेन-देन नहीं है अभी , लेकिन केवल पर प्रतिबद्ध, अमल करने के लिए एक ही रास्ता INSERTअब यह tx के बाहर चलाने के लिए है।
ज्रोडोल्फ

12

यह लिंक अच्छे तरीके से समझाता है:

http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/

हम सभी को ये समस्याएँ होती हैं, जिनका सामना हम बार-बार करते हैं कि जब हम उन्हें फिर से देखते हैं, तो हमें पता चलता है कि हमने इसे हल कर लिया है, लेकिन याद नहीं कर सकते कि कैसे।

हाइबरनेट में Session.saveOrUpdate () का उपयोग करते समय फेंके गए NonUniqueObjectException मेरा एक है। मैं एक जटिल अनुप्रयोग में नई कार्यक्षमता जोड़ रहा हूँ। मेरे सभी यूनिट परीक्षण ठीक काम करते हैं। तब UI का परीक्षण करने में, किसी ऑब्जेक्ट को सहेजने की कोशिश करते हुए, मुझे संदेश के साथ एक अपवाद मिलना शुरू होता है "समान पहचानकर्ता मान के साथ एक अलग ऑब्जेक्ट पहले से ही सत्र के साथ जुड़ा हुआ था।" यहां हाइबरनेट के साथ जावा पर्सिस्टेंस के कुछ उदाहरण कोड दिए गए हैं।

            Session session = sessionFactory1.openSession();
            Transaction tx = session.beginTransaction();
            Item item = (Item) session.get(Item.class, new Long(1234));
            tx.commit();
            session.close(); // end of first session, item is detached

            item.getId(); // The database identity is "1234"
            item.setDescription("my new description");
            Session session2 = sessionFactory.openSession();
            Transaction tx2 = session2.beginTransaction();
            Item item2 = (Item) session2.get(Item.class, new Long(1234));
            session2.update(item); // Throws NonUniqueObjectException
            tx2.commit();
            session2.close();

इस अपवाद के कारण को समझने के लिए, अलग-थलग वस्तुओं को समझना महत्वपूर्ण है और जब आप किसी अलग ऑब्जेक्ट पर saveOrUpdate () (या सिर्फ अपडेट ()) कॉल करते हैं तो क्या होता है।

जब हम एक व्यक्ति हाइबरनेट सत्र को बंद करते हैं, तो जिन स्थायी वस्तुओं के साथ हम काम कर रहे हैं वे अलग हो जाते हैं। इसका मतलब है कि डेटा अभी भी एप्लिकेशन की मेमोरी में है, लेकिन हाइबरनेट वस्तुओं में परिवर्तन पर नज़र रखने के लिए ज़िम्मेदार नहीं है।

यदि हम फिर अपनी अलग की गई वस्तु को संशोधित करते हैं और उसे अद्यतन करना चाहते हैं, तो हमें उस वस्तु को फिर से बदलना होगा। उस पुनरावृत्ति प्रक्रिया के दौरान, हाइबरनेट यह देखने के लिए जांच करेगा कि क्या उसी वस्तु की कोई अन्य प्रतियां हैं या नहीं। यदि यह किसी को भी मिल जाता है, तो हमें यह बताना होगा कि यह नहीं जानता कि "वास्तविक" कॉपी कोई और है। शायद उन अन्य प्रतियों में अन्य परिवर्तन किए गए थे जो हम सहेजने की उम्मीद करते हैं, लेकिन हाइबरनेट उनके बारे में नहीं जानता, क्योंकि यह उस समय उन्हें प्रबंधित नहीं कर रहा था।

संभवतः खराब डेटा को बचाने के बजाय, हाइबरनेट हमें NonUniqueObjectException के माध्यम से समस्या के बारे में बताता है।

तो हम क्या करें? हाइबरनेट 3 में, हमारे पास मर्ज है () और हाइबरनेट 2 में, saveOrUpdateCopy ()) का उपयोग करें। यह विधि हाइबरनेट को आपके द्वारा सहेजे जाने वाले उदाहरण पर अन्य अलग किए गए उदाहरणों से किसी भी परिवर्तन को कॉपी करने के लिए बाध्य करेगी, और इस तरह से सहेजने से पहले मेमोरी में सभी परिवर्तनों को मर्ज करता है।

        Session session = sessionFactory1.openSession();
        Transaction tx = session.beginTransaction();
        Item item = (Item) session.get(Item.class, new Long(1234));
        tx.commit();
        session.close(); // end of first session, item is detached

        item.getId(); // The database identity is "1234"
        item.setDescription("my new description");
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        Item item2 = (Item) session2.get(Item.class, new Long(1234));
        Item item3 = session2.merge(item); // Success!
        tx2.commit();
        session2.close();

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

यह भी ध्यान रखना महत्वपूर्ण है कि जावा पर्सिस्टेंस एपीआई (JPA) में अलग और हटाई गई वस्तुओं की अवधारणा नहीं है, और EntityManager.persist () और EntityManager.merge () का उपयोग करता है।

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

आपने इस समस्या का सामना कहाँ किया है? क्या आपके लिए मर्ज काम किया गया या आपको किसी अन्य समाधान की आवश्यकता थी? क्या आप हमेशा मर्ज का उपयोग करना पसंद करते हैं, या केवल विशिष्ट मामलों के लिए आवश्यकतानुसार इसका उपयोग करना पसंद करते हैं


Webarchive पर लेख का लिंक, क्योंकि मूल उपलब्ध नहीं है: web.archive.org/web/20160521091122/http://www.stevideter.com:80/…
Eugen Labun

5

वास्तव में हाइबरनेट save()और persist()विधियों के बीच का अंतर जनरेटर वर्ग पर निर्भर करता है जिसका हम उपयोग कर रहे हैं।

यदि हमारा जनरेटर वर्ग सौंपा गया है, तो तरीकों save()और persist() के बीच कोई अंतर नहीं है । क्योंकि जनरेटर 'असाइन' का अर्थ है, एक प्रोग्रामर के रूप में हमें डेटाबेस में सहेजने के लिए प्राथमिक कुंजी मान देने की आवश्यकता है [आशा है कि आप इस जनरेटर अवधारणा को जानते हैं] नियत जनरेटर वर्ग के अलावा अन्य मामलों में, मान लें कि हमारे जनरेटर वर्ग का नाम वृद्धि का मतलब है हाइबरनेट यह स्वयं डेटाबेस में प्राथमिक कुंजी आईडी मान को नियत करेगा [असाइन किए गए जनरेटर के अलावा, हाइबरनेट केवल प्राथमिक कुंजी आईडी मान को ध्यान में रखने के लिए उपयोग किया जाता है], इसलिए इस मामले में यदि हम कॉल save()या persist()विधि करते हैं तो यह रिकॉर्ड सम्मिलित करेगा। डेटाबेस सामान्य रूप से लेकिन सुनने की बात है, save()विधि उस प्राथमिक कुंजी आईडी मान को वापस कर सकती है जो हाइबरनेट द्वारा उत्पन्न होता है और हम इसे देख सकते हैं

long s = session.save(k);

इस मामले में, persist()ग्राहक को कोई मूल्य वापस नहीं देगा।


5

मुझे एक अच्छा उदाहरण मिला जो सभी हाइबरनेट बचाने के तरीकों के बीच अंतर दिखा रहा है:

http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

संक्षेप में, उपरोक्त लिंक के अनुसार:

सहेजें()

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

जारी रहती है ()

  • लेन-देन में बचाने () का उपयोग करने के समान है, इसलिए यह सुरक्षित है और किसी भी कैस्केड ऑब्जेक्ट का ख्याल रखता है।

saveOrUpdate ()

  • लेन-देन के साथ या बिना उपयोग किया जा सकता है, और जैसे बचत (), यदि इसका उपयोग लेनदेन के बिना किया जाता है, तो मैप किए गए संस्थाओं को संयुक्त राष्ट्र में सहेजा जा सकता है;

  • प्रदान किए गए डेटा के आधार पर प्रश्नों को सम्मिलित करें या अपडेट करें। यदि डेटा डेटाबेस में मौजूद है, तो अद्यतन क्वेरी निष्पादित की जाती है।

अपडेट करें()

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

मर्ज ()

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

इन सभी के व्यावहारिक उदाहरणों के लिए, कृपया ऊपर बताए गए लिंक को देखें, यह इन सभी विभिन्न तरीकों के लिए उदाहरण दिखाता है।


3

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

एक जेपीए या हाइबरनेट इकाई निम्नलिखित चार राज्यों में से एक में हो सकती है:

  • क्षणिक (नया)
  • प्रबंधित (लगातार)
  • जुदा जुदा
  • हटाया (हटाए गए)

एक राज्य से दूसरे में संक्रमण EntityManager या सत्र विधियों के माध्यम से किया जाता है।

उदाहरण के लिए, जेपीए EntityManagerनिम्नलिखित इकाई राज्य संक्रमण के तरीके प्रदान करता है।

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

हाइबरनेट Sessionसभी जेपीए EntityManagerविधियों को लागू करता है और कुछ अतिरिक्त इकाई राज्य संक्रमण विधियों जैसे save, saveOrUpdateऔर प्रदान करता है update

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

दृढ़ रहना

ट्रांसिएंट (नया) से प्रबंधित (स्थायी) के लिए एक इकाई की स्थिति को बदलने के लिए, हम persistजेपीए द्वारा प्रस्तुत विधि का उपयोग कर सकते हैं EntityManagerजो कि हाइबरनेट द्वारा विरासत में मिला है Session

यह persistविधि हाइबरनेट इवेंट श्रोता PersistEventद्वारा नियंत्रित की जाती DefaultPersistEventListenerहै।

इसलिए, निम्नलिखित परीक्षण मामले को निष्पादित करते समय:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    LOGGER.info(
        "Persisting the Book entity with the id: {}", 
        book.getId()
    );
});

हाइबरनेट निम्नलिखित SQL कथन उत्पन्न करता है:

CALL NEXT VALUE FOR hibernate_sequence

-- Persisting the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

ध्यान दें कि इकाई को वर्तमान दृढ़ता संदर्भ में idसंलग्न करने से पहले सौंपा गया है Book। यह आवश्यक है क्योंकि प्रबंधित इकाइयां एक Mapसंरचना में संग्रहीत होती हैं जहां कुंजी इकाई प्रकार और उसके पहचानकर्ता द्वारा बनाई जाती है और मूल्य इकाई संदर्भ होता है। यही कारण है कि जेपीए EntityManagerऔर हाइबरनेट Sessionको प्रथम-स्तरीय कैश के रूप में जाना जाता है।

कॉल करते समय persist, इकाई केवल वर्तमान में चल रहे परिप्रेक्ष्य से जुड़ी होती है, और INSERT flushको कॉल किए जाने तक स्थगित किया जा सकता है।

एकमात्र अपवाद पहचान जनरेटर है जो तुरंत INSERT को ट्रिगर करता है क्योंकि यह एकमात्र तरीका है जिससे यह इकाई पहचानकर्ता प्राप्त कर सकता है। इस कारण से, हाइबरनेट IDENTITY जनरेटर का उपयोग कर संस्थाओं के लिए बैच आवेषण नहीं कर सकता है। इस विषय के बारे में अधिक जानकारी के लिए, इस लेख को देखें

सहेजें

हाइबरनेट-विशिष्ट saveविधि जेपीए से पहले की है और यह हाइबरनेट परियोजना की शुरुआत के बाद से उपलब्ध है।

यह saveविधि हाइबरनेट इवेंट श्रोता SaveOrUpdateEventद्वारा नियंत्रित की जाती DefaultSaveOrUpdateEventListenerहै। इसलिए, saveविधि updateऔर saveOrUpdateविधियों के बराबर है ।

यह देखने के लिए कि saveविधि कैसे काम करती है, निम्नलिखित परीक्षण मामले पर विचार करें:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);

    Long id = (Long) session.save(book);

    LOGGER.info(
        "Saving the Book entity with the id: {}", 
        id
    );
});

ऊपर परीक्षण केस चलाते समय, हाइबरनेट निम्नलिखित SQL कथन उत्पन्न करता है:

CALL NEXT VALUE FOR hibernate_sequence

-- Saving the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

जैसा कि आप देख सकते हैं, परिणाम persistविधि कॉल के समान है । हालाँकि, इसके विपरीत persist, saveविधि निकाय पहचानकर्ता देता है।

अधिक जानकारी के लिए, इस लेख को देखें

अपडेट करें

हाइबरनेट-विशिष्ट updateविधि का अर्थ है गंदे चेकिंग तंत्र को बायपास करना और फ्लश समय पर एक इकाई अद्यतन को मजबूर करना।

यह updateविधि हाइबरनेट इवेंट श्रोता SaveOrUpdateEventद्वारा नियंत्रित की जाती DefaultSaveOrUpdateEventListenerहै। इसलिए, updateविधि saveऔर saveOrUpdateविधियों के बराबर है ।

यह देखने के लिए कि updateविधि कैसे काम करती है, निम्नलिखित उदाहरण पर विचार करें जो Bookएक लेन-देन में एक इकाई को बनाए रखता है, फिर यह तब संशोधित करता है जब इकाई अलग स्थिति में होती है, और यह updateविधि कॉल का उपयोग करके SQL UPDATE को बाध्य करता है ।

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);

    LOGGER.info("Updating the Book entity");
});

ऊपर परीक्षण मामले को निष्पादित करते समय, हाइबरनेट निम्नलिखित SQL कथन उत्पन्न करता है:

CALL NEXT VALUE FOR hibernate_sequence

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

-- Modifying the Book entity
-- Updating the Book entity

UPDATE 
    book 
SET 
    author = 'Vlad Mihalcea', 
    isbn = '978-9730228236', 
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE 
    id = 1

ध्यान दें कि UPDATEप्रतिबद्धताओं के संदर्भ में, दृढ़ता से पहले फ्लश के दौरान निष्पादित किया जाता है, और इसीलिए Updating the Book entityसंदेश पहले लॉग किया जाता है।

@SelectBeforeUpdateअनावश्यक अपडेट से बचने के लिए उपयोग करना

अब, अद्यतन हमेशा निष्पादित किया जा रहा है भले ही इकाई को अलग-थलग अवस्था में नहीं बदला गया हो। इसे रोकने के लिए, आप @SelectBeforeUpdateहाइबरनेट एनोटेशन का उपयोग कर सकते हैं जो एक SELECTबयान को ट्रिगर करेगा loaded stateजो कि फिर गंदे जाँच तंत्र द्वारा उपयोग किया जाता है।

इसलिए, यदि हम एनोटेशन के Bookसाथ इकाई को एनोटेट करते @SelectBeforeUpdateहैं:

@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {

    //Code omitted for brevity
}

और निम्नलिखित परीक्षण मामले को निष्पादित करें:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);
});

हाइबरनेट निम्नलिखित SQL कथनों को निष्पादित करता है:

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

SELECT 
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM 
    book b
WHERE 
    b.id = 1

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

SaveOrUpdate

हाइबरनेट-विशिष्ट saveOrUpdateविधि के लिए एक उपनाम है saveऔर update

यह saveOrUpdateविधि हाइबरनेट इवेंट श्रोता SaveOrUpdateEventद्वारा नियंत्रित की जाती DefaultSaveOrUpdateEventListenerहै। इसलिए, updateविधि saveऔर saveOrUpdateविधियों के बराबर है ।

अब, आप saveOrUpdateतब उपयोग कर सकते हैं जब आप एक इकाई को बनाए रखना चाहते हैं या UPDATEनिम्नलिखित उदाहरण के अनुसार उदाहरण के लिए मजबूर कर सकते हैं ।

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle("High-Performance Java Persistence, 2nd edition");

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(_book);
});

से सावधान रहें NonUniqueObjectException

एक समस्या यह है कि साथ हो सकता है save, updateऔर saveOrUpdateअगर हठ संदर्भ पहले से ही एक ही आईडी वाले और निम्न उदाहरण में एक ही प्रकार के एक इकाई संदर्भ शामिल है:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

try {
    doInJPA(entityManager -> {
        Book book = entityManager.find(
            Book.class, 
            _book.getId()
        );

        Session session = entityManager.unwrap(Session.class);
        session.saveOrUpdate(_book);
    });
} catch (NonUniqueObjectException e) {
    LOGGER.error(
        "The Persistence Context cannot hold " +
        "two representations of the same entity", 
        e
    );
}

अब, जब ऊपर परीक्षण मामले को निष्पादित किया जाता है, तो हाइबरनेट फेंकने जा रहा है NonUniqueObjectExceptionक्योंकि दूसरे में EntityManagerपहले Bookसे ही एक पहचानकर्ता के साथ एक इकाई है जिस पर हम गुजरते हैं update, और दृढ़ता संदर्भ एक ही इकाई के दो प्रतिनिधित्व नहीं कर सकता है।

org.hibernate.NonUniqueObjectException: 
    A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)

मर्ज

से बचने के लिए NonUniqueObjectException, आपको mergeजेपीए द्वारा प्रस्तुत विधि का उपयोग करने की आवश्यकता है EntityManagerऔर Sessionसाथ ही हाइबरनेट द्वारा विरासत में मिला है ।

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

यह mergeविधि हाइबरनेट इवेंट श्रोता MergeEventद्वारा नियंत्रित की जाती DefaultMergeEventListenerहै।

यह देखने के लिए कि mergeविधि कैसे काम करती है निम्नलिखित उदाहरण पर विचार करें जो Bookएक लेनदेन में एक इकाई को बनाए रखता है, फिर यह इसे संशोधित करता है, जबकि इकाई अलग राज्य में होती है, और mergeबाद की इकाई को एक अनुशीलन परिप्रेक्ष्य संदर्भ में पारित करता है ।

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

doInJPA(entityManager -> {
    Book book = entityManager.merge(_book);

    LOGGER.info("Merging the Book entity");

    assertFalse(book == _book);
});

ऊपर परीक्षण केस चलाते समय, हाइबरनेट ने निम्नलिखित एसक्यूएल स्टेटमेंट्स को निष्पादित किया:

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

-- Modifying the Book entity

SELECT 
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM 
    book b
WHERE 
    b.id = 1

-- Merging the Book entity

UPDATE 
    book 
SET 
    author = 'Vlad Mihalcea', 
    isbn = '978-9730228236', 
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE 
    id = 1

ध्यान दें कि जिस इकाई का संदर्भ दिया गया mergeहै, वह उस अलग से अलग है जिसे हमने mergeविधि से पारित किया है ।

अब, हालांकि आपको mergeअलग इकाई स्थिति की प्रतिलिपि बनाते समय जेपीए का उपयोग करना चाहिए , SELECTबैच प्रसंस्करण कार्य को निष्पादित करते समय अतिरिक्त समस्याग्रस्त हो सकता है।

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

इस विषय के बारे में अधिक जानकारी के लिए, इस लेख को देखें

निष्कर्ष

एक इकाई को बनाए रखने के लिए, आपको जेपीए persistपद्धति का उपयोग करना चाहिए । अलग निकाय राज्य की प्रतिलिपि बनाने के लिए, mergeप्राथमिकता दी जानी चाहिए। updateविधि बैच प्रोसेसिंग कार्यों के लिए ही उपयोगी है। saveऔर saveOrUpdateकरने के लिए सिर्फ उपनाम हैं updateऔर आप शायद सब पर उन्हें इस्तेमाल नहीं करना चाहिए।

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

अधिक जानकारी के लिए, इस लेख को देखें


2

इस बात से अवगत रहें कि यदि आप किसी अलग ऑब्जेक्ट पर अपडेट कहते हैं, तो डेटाबेस में हमेशा एक अपडेट होगा कि आपने ऑब्जेक्ट को बदला या नहीं। यदि यह नहीं है कि आप क्या चाहते हैं तो आपको LockMode.None के साथ Session.lock () का उपयोग करना चाहिए।

आपको केवल तभी कॉल करना चाहिए जब ऑब्जेक्ट आपके वर्तमान सत्र के दायरे से बाहर बदल गया हो (जब अलग मोड में हो)।


1

निम्नलिखित में से कोई भी उत्तर सही नहीं है। ये सभी तरीके सिर्फ एक जैसे प्रतीत होते हैं, लेकिन व्यवहार में बिल्कुल अलग चीजें करते हैं। छोटी टिप्पणियाँ देना कठिन है। इन विधियों के बारे में पूर्ण प्रलेखन का लिंक देने के लिए बेहतर है: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html


11
कृपया हमें बताएं कि निम्नलिखित उत्तर सही क्यों नहीं हैं।
एरान मोराद

0

उपरोक्त में से कोई भी उत्तर पूर्ण नहीं है। यद्यपि लियो थोबाल्ड उत्तर निकटतम उत्तर दिखता है।

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

कभी भी HIBERNATE के बचाने के तरीके का उपयोग न करें। यह पता लगाने में यह साबित होता है कि भूल जाओ!

दृढ़ रहना

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

इस बिंदु पर, यदि आप फिर से "दृढ़ता" करते हैं तो कोई बदलाव नहीं होगा। और अगर हम एक निरंतर अस्तित्व को बनाए रखने की कोशिश करते हैं तो कोई और बचत नहीं होगी।

मज़ा तब शुरू होता है जब हम इकाई को बेदखल करने की कोशिश करते हैं।

बेदखल हाइबरनेट का एक विशेष कार्य है जो इकाई को "प्रबंधित" से "डिटैच" में परिवर्तित कर देगा। हम एक अलग इकाई पर एक दृढ़ता नहीं कह सकते। यदि हम ऐसा करते हैं, तो हाइबरनेट एक अपवाद उठाता है और पूरा लेनदेन वापस चालू हो जाता है।

मर्ज बनाम अपडेट

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

एक तथ्य को समझें कि अलग किया गया मतलब एक "ऑफ़लाइन" स्थिति है। और प्रबंधित का अर्थ है "ऑनलाइन" राज्य।

नीचे दिए गए कोड को देखें:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.merge(entity);

    ses1.delete(entity);

    tx1.commit();

जब आप ऐसा करते हैं? तुम्हें क्या लगता है क्या होगा? यदि आपने कहा कि यह अपवाद को बढ़ाएगा, तो आप सही हैं। यह अपवाद को बढ़ाएगा क्योंकि, मर्ज ने इकाई वस्तु पर काम किया है, जो अलग राज्य है। लेकिन यह वस्तु की स्थिति में परिवर्तन नहीं करता है।

दृश्य के पीछे, मर्ज एक चयनित क्वेरी बढ़ाएगा और मूल रूप से इकाई की एक प्रति लौटाएगा जो संलग्न स्थिति में है। नीचे दिए गए कोड को देखें:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();
    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    HibEntity copied = (HibEntity)ses1.merge(entity);
    ses1.delete(copied);

    tx1.commit();

उपरोक्त नमूना काम करता है क्योंकि मर्ज ने एक नई इकाई को संदर्भ में लाया है जो निरंतर स्थिति में है।

जब अपडेट के साथ आवेदन किया जाता है तो वही काम ठीक होता है क्योंकि अपडेट वास्तव में मर्ज जैसी संस्था की कॉपी नहीं लाता है।

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.update(entity);

    ses1.delete(entity);

    tx1.commit();

डीबग ट्रेस में एक ही समय में हम देख सकते हैं कि अपडेट ने मर्ज की तरह एसक्यूएल क्वेरी को नहीं उठाया है।

हटाना

उपरोक्त उदाहरण में मैंने डिलीट के बारे में बात किए बिना डिलीट का उपयोग किया। हटाएं मूल रूप से निकाय को प्रबंधित स्थिति से "हटाए गए" स्थिति में बदल देगी। और जब फ्लश या कमिट किया जाएगा तो स्टोर करने के लिए एक डिलीट कमांड जारी होगी।

हालांकि यह जारी रखने की विधि का उपयोग करके "हटाए गए" राज्य से इकाई को "प्रबंधित" स्थिति में वापस लाना संभव है।

आशा है कि उपरोक्त स्पष्टीकरण से किसी भी संदेह को स्पष्ट किया जा सकता है।

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