हाइबरनेट - बैच अपडेट ने अपडेट से अप्रत्याशित पंक्ति गणना लौटा दी: 0 वास्तविक पंक्ति गणना: 0 अपेक्षित: 1


141

मुझे हाइबरनेट त्रुटि के बाद मिलता है। मैं उस फ़ंक्शन की पहचान करने में सक्षम हूं जो समस्या का कारण बनता है। दुर्भाग्य से फ़ंक्शन में कई DB कॉल हैं। मैं उस लाइन का पता लगाने में असमर्थ हूं, जो लेन-देन के अंत में सत्र को हाइबरनेट करने के बाद समस्या का कारण बनता है। नीचे उल्लिखित हाइबरनेट त्रुटि एक सामान्य त्रुटि की तरह दिखती है। यह उल्लेख भी नहीं है कि बीन किस मुद्दे का कारण बनता है। इस हाइबरनेट त्रुटि से कोई परिचित है?

org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
        at org.hibernate.jdbc.BatchingBatcher.checkRowCount(BatchingBatcher.java:93)
        at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:79)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:195)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:584)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransacti
onManager.java:500)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManag
er.java:473)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.doCommitTransactionAfterReturning(Transaction
AspectSupport.java:267)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)

शुक्रिया @ पेटर मोर्टेंसन। मैंने अपना ईमेल अपडेट कर दिया है।
सूजी

मेरी भी यही समस्या है। यह बहुत बड़ा मुद्दा नहीं है क्योंकि यह बहुत कम ही होता है। Show_sql का उपयोग करना व्यावहारिक नहीं है क्योंकि इस व्यवहार को पुन: प्रस्तुत करने के लिए लाखों लेनदेन की आवश्यकता होती है। हालाँकि, क्योंकि ऐसा बार-बार होने वाले सिस्टम टेस्ट के दौरान होता है (जिसमें लेन-देन का गजिलियन होता है) मुझे संदेह है कि एक विशिष्ट कारण है।
daniel_or_else 7

मुझे इस समस्या का सामना करना पड़ा जब मैंने उन पंक्तियों को अपडेट करने की कोशिश की जिनमें कोई परिवर्तन नहीं है। अंतर न होने पर कुछ अपडेट न करें।
फिफ्टी

जवाबों:


62

आपके लेनदेन के लिए कोड और मैपिंग के बिना, समस्या की जांच करना असंभव के बगल में होगा।

हालाँकि, समस्या के कारणों को बेहतर तरीके से संभालने के लिए, निम्नलिखित प्रयास करें:

  • अपने हाइबरनेट कॉन्फ़िगरेशन में, hibernate.show_sql को सही पर सेट करें। यह आपको SQL को निष्पादित करता है और समस्या का कारण बनता है।
  • स्प्रिंग और हाइबरनेट के लिए लॉग स्तर DEBUG पर सेट करें, फिर से यह आपको एक बेहतर विचार देगा कि कौन सी रेखा समस्या का कारण बनती है।
  • एक इकाई परीक्षण बनाएं जो स्प्रिंग में लेनदेन प्रबंधक को कॉन्फ़िगर किए बिना समस्या की नकल करता है। यह आपको कोड की आपत्तिजनक रेखा का बेहतर विचार देना चाहिए।

उम्मीद है की वो मदद करदे।


21
hibernate.show_sql> मैं DEBUG को लॉग श्रेणी org.hibernate.SQL स्तर सेट करने के लिए सलाह दूंगा। इस तरह आपको केवल लॉगिंग के लिए हाइबरनेट कॉन्फ़िगरेशन को संशोधित करने की आवश्यकता नहीं है।
थिएरी

"Show_sql" का उपयोग बहुत ही क्रियात्मक हो सकता है और उत्पादन में व्यावहारिक नहीं हो सकता है। इसके लिए मैंने स्टेटमेंट को BatchingBatcher वर्ग के लाइन 74 पर पकड़ को संशोधित किया है ताकि स्टेटमेंट को ps.toString () के साथ केवल उस स्टेटमेंट के लिए प्रिंट किया जा सके जिसमें समस्या है।
Orden

71

मुझे Id द्वारा रिकॉर्ड हटाते समय एक ही अपवाद मिला जो कि मौजूद नहीं है। तो जांच लें कि आप जो रिकॉर्ड अपडेट कर रहे हैं / हटा रहे हैं वह वास्तव में डीबी में मौजूद है


12
मुझे यह समस्या तब हुई जब मैंने माता-पिता-बच्चे के रिश्ते से एक बच्चे को हटा दिया, माता-पिता (जो बच्चे को हटा देता है) को बचाया और फिर बच्चे को मैन्युअल रूप से हटाने की भी कोशिश की।
डेब थिएबेन

इससे मेरी समस्या हल हो गई। रिकॉर्ड मौजूद नहीं था और मेरी सेवा updateAll () विधि को कॉल कर रही थी, जबकि इसे वास्तव में createOrUpdateAll () विधि को कॉल करने की आवश्यकता थी। धन्यवाद।
मिताल प्रितमनी २ 28'१४ को १२:०४

3
तो इस मुद्दे को कैसे हल करें? अगर मुझे एक रिकॉर्ड मिलता है, और फिर इसे हटा दें; लेकिन अगर सिस्टम हटाने से पहले ही इसे हटा देता है, तो दूसरा, मेरा आवेदन अपवाद को फेंक देगा।
स्टोनी

@ डावेथीबेन, यह ठीक वही जानकारी थी जिसकी मुझे जरूरत थी। मुझे महसूस नहीं हुआ कि माता-पिता-बच्चे का संबंध नष्ट होने पर कायम है।
बर्फ

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

55

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

यदि आप स्पष्ट रूप से आईडी प्रॉपर्टी का मूल्य निर्धारित करते हैं, तो यह ऊपर की त्रुटि का नेतृत्व करेगा। इस त्रुटि से बचने के लिए इसे जांचें। या यह त्रुटि दिखाती है जब आप मैपिंग फ़ाइल में उल्लेख करते हैं फ़ील्ड जनरेटर = "देशी" या "वृद्धिशील" और आपके डेटा में तालिका मैप की गई auto_incremented समाधान नहीं है: अपने डेटा पर जाएं और auto_increment सेट करने के लिए अपनी तालिका को अपडेट करें


2
बिल्कुल सही। यह सही उत्तर होना चाहिए। धन्यवाद @ रदा बिरमनē
कुलदीप वर्मा

1
हालाँकि , आप ID मान को '0' पर सेट कर सकते हैं, और फिर हाइबरनेट इसे अधिलेखित करने के लिए स्वतंत्र महसूस करेगा
forresthopkinsa

1
धन्यवाद! यकीन नहीं है कि यह उच्चतम रैंक वाला उत्तर क्यों नहीं है।
स्टुअर्ट मैकइंटायर

18

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


15

मेरे मामले में, मैं दो समान मामलों में इस अपवाद पर आया था:

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

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

समाधान: समस्या को हल करने के लिए, आपको अपनी आवश्यकताओं को पूरा करने वाले को खोजने के लिए हाइबरनेट लॉकमोड के साथ खेलना होगा ।


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

1
यह एक लंबा समय था क्योंकि मुझे समस्या थी और मुझे अच्छी तरह से सटीक समाधान याद नहीं है जो मैंने जगह में रखा है, लेकिन यह LockMode.READया था LockMode.OPTIMISTIC
सर्जियो लीमा

13

मुझे बस इस समस्या का सामना करना पड़ा और मुझे पता चला कि मैं एक रिकॉर्ड हटा रहा था और बाद में इसे हाइबरनेट लेनदेन में अपडेट करने की कोशिश कर रहा था।


9

यह तब हो सकता है जब ट्रिगर (एस) अतिरिक्त डीएमएल (डेटा संशोधन) प्रश्नों को निष्पादित करते हैं जो पंक्ति गणना को प्रभावित करते हैं। मेरा समाधान मेरे ट्रिगर के शीर्ष पर निम्नलिखित जोड़ना था:

SET NOCOUNT ON;

1
इस जवाब ने मुझे सही दिशा में भेजा। मैं एक विरासत डेटाबेस के साथ काम कर रहा था, जिस पर एक ट्रिगर था - सौभाग्य से मैं बदल रहा था कि ट्रिगर ने कोड के साथ क्या किया, इसलिए मैं बस इसे हटा सकता था।
एस। बग्गी जूल

2
+1 यह भी मेरी समस्या थी। मैं postgresql का उपयोग कर रहा था, इसलिए पंक्ति गणना की जाँच करने के लिए स्विच करने के लिए @SQLInsert एनोटेशन का उपयोग करने की आवश्यकता थी: technology-ebay.de/the-teams/mobile-de/blog/…
s1mm03

सेट नॉट ऑफ *
जी। सिराडिनी

7

मैं उसी मुद्दे का सामना कर रहा था। परीक्षण वातावरण में कोड काम कर रहा था। लेकिन यह मंचन के माहौल में काम नहीं कर रहा था।

org.hibernate.jdbc.BatchedTooManyRowsAffectedException: Batch update returned unexpected row count from update [0]; actual row count: 3; expected: 1

समस्या यह थी कि तालिका में DB तालिका के परीक्षण में प्रत्येक प्राथमिक कुंजी के लिए एकल प्रविष्टि थी। लेकिन DB के मंचन में एक ही प्राथमिक कुंजी के लिए कई प्रविष्टि थी। (समस्या डीबी के मंचन में है, जिसमें कोई मुख्य कुंजी बाधा नहीं थी, जिसमें कई प्रविष्टि भी थी।)

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

के बाद मैंने उन सभी रिकॉर्डों को हटा दिया, जिनमें प्राथमिक कुंजी की डुप्लिकेट है और प्राथमिक कुंजी की कमी को जोड़ा है। यह ठीक काम कर रहा है।

Hibernate - Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1

वास्तविक पंक्ति गणना: 0 // का मतलब है कि अपडेट को अपडेट करने के लिए कोई रिकॉर्ड नहीं मिला
: 0 // का मतलब है कि कोई रिकॉर्ड नहीं मिला, इसलिए कुछ भी अपडेट
होने की उम्मीद नहीं है: 1 // का मतलब है db टेबल में कुंजी के साथ कम से कम 1 रिकॉर्ड।

यहाँ समस्या यह है कि क्वेरी कुछ कुंजी के लिए रिकॉर्ड अपडेट करने की कोशिश कर रही है, लेकिन हाइबरनेट को कुंजी के साथ कोई रिकॉर्ड नहीं मिला।


हाय @ParagFlume, मुझे एक ही त्रुटि मिली "बैच अपडेट ने अपडेट से अनपेक्षित पंक्ति गणना लौटा दी: 0 वास्तविक पंक्ति गणना: 0 अपेक्षित: 1" जब मैं अपने डेटाबेस से किसी एक ऑब्जेक्ट का चयन करने का प्रयास करता हूं तो समस्या केवल किसी भी उत्पादन में मौजूद होती है, क्या आप किसी भी इस समस्या को हल करने के बारे में विचार, मैं एक गंभीर स्थिति में हूँ। सादर !
जेम्स

मुझे लगता है कि क्वेरी को db में कोई रिकॉर्ड नहीं मिला, यह db में एक रिकॉर्ड खोजने की उम्मीद कर रहा है, जिसे वह अपडेट करने की कोशिश कर रहा है। यदि आप वास्तव में db पर मौजूद हैं, तो आप मैन्युअल रूप से / क्वेरी-ब्राउज़र देख सकते हैं।
ParagFlume

हाँ रिकॉर्ड मौजूद है, लेकिन मेरी समस्या यह है कि हाइबरनेट को अपडेट करने की कोशिश की जा रही है, मैं डेटाबेस से ऑब्जेक्ट प्राप्त करने के लिए एक चुनिंदा सेवा का उपयोग कर रहा हूं!
जेम्स

हो सकता है कि आप वस्तुओं की स्थिति को बदलने की कोशिश कर रहे हों। और सत्र अभी भी खुला है।
ParagFlume

मैं इस व्यवहार की जांच कैसे कर सकता हूं, क्योंकि मैं वह व्यक्ति नहीं हूं जो सेवा का विकास करता है ...
जेम्स

5

जैसा कि जूलियस का कहना है कि ऐसा तब होता है जब एक अपडेट एक ऐसी वस्तु पर होता है जिसमें उसके बच्चों को हटा दिया जाता है। (शायद इसलिए कि पूरे फादर ऑब्जेक्ट के लिए एक अपडेट की आवश्यकता थी और कभी-कभी हम बच्चों को हटाना पसंद करते हैं और उन्हें फ़ादर (नए, पुराने महत्वपूर्ण मामले) पर पुन: प्रकाशित करते हैं, साथ ही साथ पिता द्वारा किए गए किसी भी अन्य अपडेट पर इसके अन्य मैदानी क्षेत्र) तो ... इसके लिए बच्चों को कॉल करके childrenList.clear()( एक लेनदेन के भीतर) काम करने के लिए (बच्चों के माध्यम से लूप न करें ) और प्रत्येक को कुछ childDAO.delete(childrenList.get(i).delete()))और सेटिंग के साथ हटा दें@OneToMany(cascade = CascadeType.XXX ,orphanRemoval=true)पिता वस्तु की तरफ। फिर पिता (पितादेव) को अपडेट करें (पिता) (पिता)। (प्रत्येक पिता वस्तु के लिए दोहराएं) इसका परिणाम यह है कि बच्चों के पास उनके पिता से उनका लिंक छीन लिया जाता है और फिर उन्हें फ्रेमवर्क द्वारा अनाथ के रूप में हटा दिया जाता है।


5

मुझे इस समस्या का सामना करना पड़ा जहां हमारे बीच कई संबंध थे।

मास्टर के लिए हाइबरनेट hbm मैपिंग फ़ाइल में, सेट प्रकार की व्यवस्था के साथ ऑब्जेक्ट के लिए, जोड़ा गया cascade="save-update"और यह ठीक काम किया।

इसके बिना, डिफ़ॉल्ट हाइबरनेट एक गैर-मौजूद रिकॉर्ड के लिए अद्यतन करने की कोशिश करता है और ऐसा करने के बजाय यह आवेषण करता है।



3

मुझे वही समस्या मिली और मैंने सत्यापित किया कि ऑटो इंक्रीमेंट की प्राथमिक कुंजी के कारण यह हो सकता है। इस समस्या को हल करने के लिए डेटा सेट के साथ ऑटो इंक्रीमेंट वैल्यू इनसेट न करें। प्राथमिक कुंजी के बिना डेटा डालें।


3

इस त्रुटि को प्राप्त करने का एक और तरीका है यदि आपके पास संग्रह में एक शून्य आइटम है।


2

यह तब होता है जब आप उसी ऑब्जेक्ट को हटाने की कोशिश करते हैं और फिर डिलीट होने के बाद उसी ऑब्जेक्ट को फिर से अपडेट करते हैं

session.clear ();


2

मेरे साथ भी ऐसा ही हुआ, क्योंकि मेरे पास मेरी आईडी लॉन्ग के रूप में थी, और मुझे यह मान 0 मान से प्राप्त हो रहा था, और जब मैंने डेटाबेस में सहेजने की कोशिश की तो मुझे यह त्रुटि मिली, फिर मैंने इसे आईडी सेट करके शून्य करने के लिए निर्धारित किया।


1

मैं इस मुद्दे में भाग गया जब मैं मैन्युअल रूप से शुरुआत कर रहा था और विधि के अंदर लेनदेन कर रहा था जैसा कि एनोटेट किया गया था @Transactional। यदि एक सक्रिय लेनदेन पहले से मौजूद है, तो मैंने यह पता लगाकर समस्या को ठीक किया।

//Detect underlying transaction
if (session.getTransaction() != null && session.getTransaction().isActive()) {
    myTransaction = session.getTransaction();
    preExistingTransaction = true;
} else {
    myTransaction = session.beginTransaction();
}

तब मैंने स्प्रिंग को लेन-देन करने की अनुमति दी।

private void finishTransaction() {
    if (!preExistingTransaction) {
        try {
            tx.commit();
        } catch (HibernateException he) {
            if (tx != null) {
                tx.rollback();
            }
            log.error(he);
        } finally {
            if (newSessionOpened) {
                SessionFactoryUtils.closeSession(session);
                newSessionOpened = false;
                maxResults = 0;
            }
        }
    }
}

1

यह तब होता है जब आपने JSF प्रबंधित बीन को घोषित किया था

@RequestScoped;

जब आपको घोषित करना चाहिए

@SessionScoped;

सादर;


1

मुझे यह त्रुटि तब हुई जब मैंने किसी ऑब्जेक्ट को एक आईडी के साथ अपडेट करने का प्रयास किया जो डेटाबेस में मौजूद नहीं था। मेरी गलती का कारण यह था कि मैंने मैन्युअल रूप से ऑब्जेक्ट के क्लाइंट साइड JSON-प्रतिनिधित्व के लिए 'id' नाम के साथ एक संपत्ति सौंपी थी और फिर जब सर्वर साइड पर ऑब्जेक्ट को डीरिशियल किया गया तो यह 'id' प्रॉपर्टी उदाहरण चर को अधिलेखित कर देगी ( जिसे 'id' भी कहा जाता है) जो कि हाइबरनेट उत्पन्न करने वाला था। यदि आप पहचानकर्ता उत्पन्न करने के लिए हाइबरनेट का उपयोग कर रहे हैं तो टकराव के नामकरण से सावधान रहें।


1

मैं भी उसी चुनौती पर आया था। मेरे मामले में मैं एक ऐसी वस्तु को अपडेट कर रहा था जो कि विद्यमान नहीं थी, उपयोग कर रही थी hibernateTemplate

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

मैं hibernateTemplateCRUD ऑपरेशन के लिए उपयोग कर रहा हूं ।


1

सभी उत्तरों को पढ़ने के बाद हाइबरनेट के व्युत्क्रम के बारे में बात करने के लिए किसी को भी नहीं मिला।

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

मान लें कि हमारे पास दो टेबल हैं:

प्रिंसिपल_एजेंट , मिडिल_टेबल

एक से कई के रिश्ते के साथ । हाइबरनेट मानचित्रण कक्षाएं क्रमशः प्रिंसिपल और मध्य हैं।

तो प्रिंसिपल वर्ग में मध्य वस्तुओं का एक सेट है । Xml मैपिंग फ़ाइल निम्नानुसार होनी चाहिए:

<hibernate-mapping>
    <class name="path.to.class.Principal" table="principal_table" ...>
    ...
    <set name="middleObjects" table="middle_table" inverse="true" fetch="select">
        <key>
            <column name="PRINCIPAL_ID" not-null="true" />
        </key>
        <one-to-many class="path.to.class.Middel" />
    </set>
    ...

जैसा कि उलटा "सही" पर सेट है, इसका मतलब है "मध्य" वर्ग रिश्ते का मालिक है, इसलिए प्रिंसिपल वर्ग रिश्ते को अद्यतन नहीं करेगा ।

तो अद्यतन करने की प्रक्रिया इस तरह लागू की जा सकती है:

session.beginTransaction();

Principal principal = new Principal();
principal.setSomething("1");
principal.setSomethingElse("2");


Middle middleObject = new Middle();
middleObject.setSomething("1");

middleObject.setPrincipal(principal);
principal.getMiddleObjects().add(middleObject);

session.saveOrUpdate(principal);
session.saveOrUpdate(middleObject); // NOTICE: you will need to save it manually

session.getTransaction().commit();

यह मेरे लिए काम कर रहा है, बू आप समाधान को बेहतर बनाने के लिए कुछ संस्करणों का सुझाव दे सकते हैं। इस तरह हम सभी सीखते रहेंगे।


1

हमारे मामले में हमें आखिरकार StaleStateException का मूल कारण पता चला।

वास्तव में हम एकल हाइबरनेट सत्र में दो बार पंक्ति को हटा रहे थे। पहले हम ojdbc6 lib का उपयोग कर रहे थे, और इस संस्करण में यह ठीक था।

लेकिन जब हमने odjc7 या ojdbc8 में अपग्रेड किया, तो दो बार रिकॉर्ड हटाना अपवाद फेंक रहा था। हमारे कोड में बग था, जहां हम दो बार हटा रहे थे, लेकिन ojdbc6 में यह स्पष्ट नहीं था।

हम कोड के इस टुकड़े के साथ पुन: पेश करने में सक्षम थे:

Detail detail = getDetail(Long.valueOf(1396451));
session.delete(detail);
session.flush();
session.delete(detail);
session.flush();

पहले फ्लश पर हाइबरनेट जाता है और डेटाबेस में बदलाव करता है। 2 फ्लश हाइबरनेट के दौरान सत्र की वस्तु की वास्तविक तालिका के रिकॉर्ड के साथ तुलना करता है, लेकिन एक को नहीं खोज सका, इसलिए अपवाद।


1

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

मैंने सत्र का उपयोग किया। न्याय (); पहले हाइबरनेट में संग्रहीत कैश को निकालने के लिए या यदि आप डेटा खोने का जोखिम नहीं उठाना चाहते हैं, तो बेहतर है कि आप डेटा अस्थायी को संग्रहीत करने के लिए एक और वस्तु बनाते हैं।

     try
    {
        if(!session.isOpen())
        {
            session=EmployeyDao.getSessionFactory().openSession();
        }
            tx=session.beginTransaction();

        session.evict(e);
        session.saveOrUpdate(e);
        tx.commit();;
        EmployeyDao.shutDown(session);
    }
    catch(HibernateException exc)
    {
        exc.printStackTrace();
        tx.rollback();
    }

1

हाइबरनेट 5.4.1 और एचएचएच -12878 मुद्दा

हाइबरनेट 5.4.1 से पहले, आशावादी लॉकिंग विफलता अपवाद (उदाहरण के लिए, StaleStateExceptionया OptimisticLockException) में असफल कथन शामिल नहीं था।

HHH-12878 मुद्दे हाइबरनेट में सुधार करने के लिए बनाया गया था ताकि जब एक आशावादी ताला अपवाद फेंक, JDBC PreparedStatementकार्यान्वयन अच्छी तरह से लॉग होता है:

if ( expectedRowCount > rowCount ) {
    throw new StaleStateException(
            "Batch update returned unexpected row count from update ["
                    + batchPosition + "]; actual row count: " + rowCount
                    + "; expected: " + expectedRowCount + "; statement executed: "
                    + statement
    );
}

परीक्षण का समय

मैंने BatchingOptimisticLockingTestअपने उच्च-प्रदर्शन जावा पर्सिस्टेंस GitHub रिपॉजिटरी में यह प्रदर्शित करने के लिए बनाया कि नया व्यवहार कैसे काम करता है।

सबसे पहले, हम एक Postइकाई को परिभाषित करेंगे जो एक @Versionसंपत्ति को परिभाषित करती है , इसलिए अंतर्निहित आशावादी लॉकिंग तंत्र को सक्षम करना है :

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    private String title;

    @Version
    private short version;

    public Long getId() {
        return id;
    }

    public Post setId(Long id) {
        this.id = id;
        return this;
    }

    public String getTitle() {
        return title;
    }

    public Post setTitle(String title) {
        this.title = title;
        return this;
    }

    public short getVersion() {
        return version;
    }
}

हम निम्नलिखित 3 कॉन्फ़िगरेशन गुणों का उपयोग करके JDBC बैचिंग को सक्षम करेंगे:

properties.put("hibernate.jdbc.batch_size", "5");
properties.put("hibernate.order_inserts", "true");
properties.put("hibernate.order_updates", "true");

हम 3 Postइकाइयाँ बनाने जा रहे हैं :

doInJPA(entityManager -> {
    for (int i = 1; i <= 3; i++) {
        entityManager.persist(
            new Post()
                .setTitle(String.format("Post no. %d", i))
        );
    }
});

और हाइबरनेट एक JDBC बैच डालने पर अमल करेगा:

SELECT nextval ('hibernate_sequence')
SELECT nextval ('hibernate_sequence')
SELECT nextval ('hibernate_sequence')

Query: [
    INSERT INTO post (title, version, id) 
    VALUES (?, ?, ?)
], 
Params:[
    (Post no. 1, 0, 1), 
    (Post no. 2, 0, 2), 
    (Post no. 3, 0, 3)
]

तो, हम जानते हैं कि JDBC बैचिंग ठीक काम करती है।

अब, चलो आशावादी लॉकिंग मुद्दे को दोहराते हैं:

doInJPA(entityManager -> {
    List<Post> posts = entityManager.createQuery("""
        select p 
        from Post p
        """, Post.class)
    .getResultList();

    posts.forEach(
        post -> post.setTitle(
            post.getTitle() + " - 2nd edition"
        )
    );

    executeSync(
        () -> doInJPA(_entityManager -> {
            Post post = _entityManager.createQuery("""
                select p 
                from Post p
                order by p.id
                """, Post.class)
            .setMaxResults(1)
            .getSingleResult();

            post.setTitle(post.getTitle() + " - corrected");
        })
    );
});

पहला लेनदेन सभी Postसंस्थाओं का चयन करता है और titleगुणों को संशोधित करता है ।

हालांकि, पहले EntityManagerफ्लश होने से पहले , हम executeSyncविधि का उपयोग करके एक दूसरे संक्रमण को निष्पादित करने जा रहे हैं ।

दूसरा लेन-देन पहले को संशोधित करता है Post, इसलिए इसकी versionवृद्धि होने जा रही है:

Query:[
    UPDATE 
        post 
    SET 
        title = ?, 
        version = ? 
    WHERE 
        id = ? AND 
        version = ?
], 
Params:[
    ('Post no. 1 - corrected', 1, 1, 0)
]

अब, जब पहला लेन-देन फ्लश करने की कोशिश EntityManagerकरेगा, तो हमें यह मिलेगा OptimisticLockException:

Query:[
    UPDATE 
        post 
    SET 
        title = ?, 
        version = ? 
    WHERE 
        id = ? AND 
        version = ?
], 
Params:[
    ('Post no. 1 - 2nd edition', 1, 1, 0), 
    ('Post no. 2 - 2nd edition', 1, 2, 0), 
    ('Post no. 3 - 2nd edition', 1, 3, 0)
]

o.h.e.j.b.i.AbstractBatchImpl - HHH000010: On release of batch it still contained JDBC statements

o.h.e.j.b.i.BatchingBatch - HHH000315: Exception executing batch [
    org.hibernate.StaleStateException: 
    Batch update returned unexpected row count from update [0]; 
    actual row count: 0; 
    expected: 1; 
    statement executed: 
        PgPreparedStatement [
            update post set title='Post no. 3 - 2nd edition', version=1 where id=3 and version=0
        ]
], 
SQL: update post set title=?, version=? where id=? and version=?

तो, आपको इस सुधार से लाभ के लिए हाइबरनेट 5.4.1 या नए में अपग्रेड करने की आवश्यकता है।


0

यह तब होता है जब आप देशी sql क्वेरी का उपयोग करके डेटा सेट में कुछ बदलते हैं लेकिन सत्र कैश में समान डेटा सेट के लिए निरंतर ऑब्जेक्ट मौजूद रहता है। Session.evict (yourObject) का उपयोग करें;


0

सत्र से ऑब्जेक्ट्स को हाइबरनेट करें। यदि ऑब्जेक्ट को 1 से अधिक उपयोगकर्ता द्वारा एक्सेस और संशोधित किया जाता है तो org.hibernate.StaleStateExceptionफेंक दिया जा सकता है। ताला बचाने या उपयोग करने से पहले इसे मर्ज / रिफ्रेश इकाई विधि से हल किया जा सकता है। अधिक जानकारी: http://java-fp.blogspot.lt/2011/09/orghibernatestalestateexception-batch.html


0

मामले में से एक

SessionFactory sf=new Configuration().configure().buildSessionFactory();
Session session=sf.openSession();

UserDetails user=new UserDetails();

session.beginTransaction();
user.setUserName("update user agian");
user.setUserId(12);
session.saveOrUpdate(user);
session.getTransaction().commit();
System.out.println("user::"+user.getUserName());

sf.close();

0

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

आशा है कि किसी भी शरीर में मदद करता है।


0

मुझे यह त्रुटि मिली क्योंकि मैंने गलती से IDउपयोग किए गए कॉलम को मैप कर दिया थाId(x => x.Id, "id").GeneratedBy.**Assigned**();

समस्या को हल करके Id(x => x.Id, "id").GeneratedBy.**Identity**();


0

यह मेरे साथ होता है क्योंकि मैं बीन क्लास में आईडी घोषणा को याद कर रहा हूं।


0

मेरे मामले में डेटाबेस के साथ एक समस्या थी क्योंकि संग्रहीत प्रोक्स में से एक सभी CPU का उपभोग कर रहा था जो उच्च DB प्रतिक्रिया समय का कारण था। एक बार यह मार डाला गया मुद्दा सुलझ गया।

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