2017-11-12 21 views
5

द्वारा किए गए परिवर्तनों मैं उपयोग कर रहा हूँ एक PostUpdateEventListener आदेश हाइबरनेट द्वारा किए गए परिवर्तनों को ट्रैक करने में के माध्यम सेमज़बूती पर नज़र रखने के हाइबरनेट

registry.appendListeners(EventType.POST_COMMIT_UPDATE, listener) 

और कुछ अन्य श्रोताओं पंजीकृत। यह पूरी तरह से काम करता है, फिर भी, मैं एक समस्या देखें:

मान लें, id से कुछ amount नज़र रखने के लिए, मैं बस हर POST_COMMIT_UPDATE पर अमल

amountByIdConcurrentMap.put(id, amount); 

(के अन्य कार्यों की अनदेखी करते हैं)। समस्या यह है कि यह कॉल प्रतिबद्धता के बाद कुछ समय होता है। तो दो के साथ एक ही इकाई को एक दूसरे के बाद जल्द ही लिखने के लिए, मैं गलत क्रम में ईवेंट प्राप्त कर सकता हूं, पुराने amount संग्रहीत के साथ समाप्त हो रहा है।

  • क्या यह वास्तव में संभव है या ऑपरेशन किसी भी तरह सिंक्रनाइज़ किए गए हैं?
  • क्या ऐसी कोई स्थिति है जिससे कम से कम ऐसी स्थिति को कैसे रोकें या कम से कम कैसे पता चल सके?

उत्तर

2

दो सवाल और एक प्रस्ताव बाद में

  1. , क्या आपको यकीन है कि आप इस अनुकूलन की जरूरत है। वहां क्वेरी करके डेटाबेस को लिखे गए राशि को क्यों न लाएं। आपको कैशिंग के साथ काम करने का कारण क्या है।

  2. आप कैसे सुनिश्चित करते हैं कि डेटाबेस को लिखने से पहले राशि की गणना ठीक से सिंक्रनाइज़ होती है, ताकि एकाधिक धागे या संभवतः नोड्स डेटा की गणना करने के लिए पुराने डेटा का उपयोग न करें और इसलिए परिणाम के ओवरराइट करें बाद में गणना?

मुझे लगता है कि आप प्रश्न संख्या 2 को सही तरीके से संभालते हैं। फिर आपको विकल्प चुनना होगा:

  1. निराशावादी लॉकिंग, इसका मतलब है कि प्रतिबद्धता से पहले आप तुरंत अपने कैश को बिना किसी शिकायत के मुद्दों को अपडेट कर सकते हैं।
  2. आशावादी लॉकिंग: उस स्थिति में आपके पास अपने डेटाबेस-रिकॉर्ड में टाइमस्टैम्प या काउंटर का एक प्रकार है, आप राशि के साथ कैश में भी डाल सकते हैं। यह मान आप यह जानने के लिए उपयोग कर सकते हैं कि हालिया मूल्य क्या है।
+0

मैं वास्तव में आशावादी लॉकिंग का उपयोग कर रहा हूं, इसलिए संभवतः मुझे टाइममैंप की तुलना करने के लिए कुछ भी नहीं चाहिए, जैसे 'map.compute (id, (k, v) -> v == null || timestamp.isAfter (v.timestamp)? नया मूल्य (टाइमस्टैम्प, राशि): v) '। यह वास्तव में सरल लगता है। – maaartinus

+0

मार्टिनस ठीक है, लेकिन यह परिवर्तन विशेष रूप से करना सुनिश्चित करें। बीच के बीच और मूल्य निर्धारित करने के बाद एक और थ्रेड सामग्री – aschoerk

+0

मार्टिनस बदल सकता है और, क्लस्टर्ड वातावरण में, जागरूक रहें कि यदि आप वितरित नहीं होते हैं, तो इन्फिनिसन की तरह, आपको कैश में नवीनतम मान नहीं दिखाई दे सकता है। – aschoerk

2

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

यदि वास्तविक समस्या आप हल कर रहे हैं तो इकाई स्थिति का कैशिंग है और यदि यह प्रश्न में इकाई के लिए द्वितीय स्तर के कैश का उपयोग करने के लिए उपयुक्त है, तो आपको एल 2 कैश को सक्षम करके बॉक्स से सब कुछ मिल जाएगा।

अन्यथा, अद्यतन श्रोताओं से सीधे मानचित्र को अपडेट करने के बजाय, आप एक निष्पादक या संदेश प्रणाली में कार्य सबमिट कर सकते हैं जो असीमित रूप से डेटाबेस से दिए गए आईडी के लिए एक नया लेनदेन और select for update राशि शुरू करेगा। फिर डीबी में संबंधित पंक्ति लॉक रखते हुए उसी लेनदेन में मानचित्र को अपडेट करें, ताकि उसी आईडी के लिए मानचित्र अपडेट क्रमशः किए जाएं।

+0

जब एल 2 कैश इसे बेहतर कर सकता है, तो इसे इंटरसेप्टर/श्रोताओं की तुलना में कुछ बेहतर तंत्र का उपयोग करना चाहिए, है ना? '+++' दूसरा उत्तर [एक साधारण समाधान का कारण बन सकता है] (https://stackoverflow.com/questions/47254385/reliably-tracking-changes-made-by-hibernate#comment81593858_47318434), आपको क्या लगता है? – maaartinus

+1

@मार्टिनस स्थिरता सुनिश्चित करने के लिए एल 2 कैश रीड-राइट कैश के लिए मुलायम ताले का उपयोग करता है और लेनदेन संबंधी कैश के लिए एक्सए प्रोटोकॉल पर निर्भर करता है, यह इकाई अद्यतन श्रोताओं का उपयोग नहीं करता है। –

+0

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

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