दिलचस्प पोस्ट
जावा डिफ़ॉल्ट स्टैक आकार गहरी एक NSArray नकल समान चौड़ाई के दो बटन सेट की सहायता की आवश्यकता JQuery के बिना JQuery के एक JSONP अनुरोध कैसे करें? फेसबुक की तरह बटन के लिए एंड्रॉइड वेबदृश्य लूप के लिए ब्याह के साथ सरणी से आइटम निकालें रेडिम सी # में संरक्षित है? इस मामले में एलिसप स्थानीय वैरिएबल का मूल्य क्यों रखता है? एंड्रॉइड पर एचटीटीपी क्लाइंट: यूएचटीएस / 3 जी के माध्यम से नं एसएसआई पर विजुअल्यूम डेटाबेस पंक्ति ट्यूपल में पूर्णांक क्यों एक 'एल' प्रत्यय है? जावास्क्रिप्ट के साथ टच स्क्रीन उपकरणों का पता लगा रहा है एक JSON स्ट्रिंग के निर्माण में विशेष वर्णों से बचने के लिए कैसे? क्या मुझे एंटिटी फ्रेमवर्क 4.1 और एमवीसी 3 के साथ डायनामिक प्रॉक्सी को सक्षम या अक्षम करना चाहिए? SQL सर्वर सर्वर प्रबंधन स्टूडियो के साथ आयात / निर्यात डेटाबेस

Django: मैं कैसे डेटाबेस प्रविष्टियों के समवर्ती संशोधन के खिलाफ की रक्षा कर सकते हैं

यदि दो या दो से अधिक उपयोगकर्ताओं द्वारा समान डेटा बेस प्रविष्टि के समवर्ती संशोधनों से बचाने के लिए कोई रास्ता है?

दूसरा प्रतिबद्ध / सहेजने का काम करने वाला उपयोगकर्ता को एक त्रुटि संदेश दिखाने के लिए स्वीकार्य होगा, लेकिन डेटा को चुपचाप ओवरराइट नहीं करना चाहिए।

मुझे लगता है कि प्रविष्टि को लॉक करना एक विकल्प नहीं है, क्योंकि एक उपयोगकर्ता "बैक" बटन का उपयोग कर सकता है या बस अपने ब्राउज़र को बंद कर सकता है, कभी भी लॉक को छोड़ कर।

वेब के समाधान से एकत्रित समाधान "Django: मैं कैसे डेटाबेस प्रविष्टियों के समवर्ती संशोधन के खिलाफ की रक्षा कर सकते हैं"

मैं Django में आशावादी लॉकिंग करता हूं:

updated = Entry.objects.filter(Q(id=e.id) && Q(version=e.version))\ .update(updated_field=new_value, version=e.version+1) if not updated: raise ConcurrentModificationException() 

उपर्युक्त कोड कस्टम मैनेजर में एक विधि के रूप में कार्यान्वित किया जा सकता है।

मैं निम्नलिखित मान्यताओं को बना रहा हूं:

  • फिल्टर ()। अद्यतन () एक एकल डेटाबेस क्वेरी में परिणाम होगा क्योंकि फिल्टर आलसी है
  • एक डेटाबेस क्वेरी परमाणु है

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

चेतावनी Django Doc :

ध्यान रखें कि अपडेट () विधि सीधे SQL कथन में कनवर्ट हो जाती है। यह सीधी अपडेट के लिए एक बड़ी कार्रवाई है। यह आपके मॉडल पर किसी भी बचत () विधियों को नहीं चलाता, या pre_save या post_save सिग्नल का उत्सर्जन करता है

यह प्रश्न थोड़ा पुराना है और मेरा जवाब थोड़ा देर हो गया है, लेकिन इसके बाद मैं समझता हूं कि यह Django 1.4 में निर्धारित किया गया है :

 select_for_update(nowait=True) 

डॉक्स देखें

एक क्वेरीस देता है जो लेनदेन के अंत तक पंक्तियों को लॉक करेगा, एक चयन सृजन … समर्थित डेटाबेस पर अद्यतन SQL कथन के लिए।

आमतौर पर, अगर किसी अन्य लेन-देन ने पहले से चयनित पंक्तियों में से एक लॉक हासिल कर लिया है, तो लॉक जारी होने तक क्वेरी अवरुद्ध हो जाएगी। अगर यह वह व्यवहार नहीं है जो आप चाहते हैं, तो select_for_update (nowait = True) को कॉल करें। इससे कॉल को गैर-अवरुद्ध करना होगा। यदि कोई विवादित लॉक पहले से किसी अन्य ट्रांज़ेक्शन द्वारा अधिग्रहण कर लिया गया है, तो डेटाबेसअर्ज तब उठाया जाएगा जब क्वेरीस का मूल्यांकन किया जाता है।

बेशक यह केवल तभी काम करेगा यदि बैक-एंड समर्थन "अपडेट के लिए चयन करें" सुविधा का समर्थन करता है, उदाहरण के लिए, sqlite नहीं करता है। दुर्भाग्य से: nowait=True MySQL द्वारा समर्थित नहीं है, वहां आपको उपयोग करना है: nowait=False , जो लॉक रिलीज़ होने तक ब्लॉक होगा।

दरअसल, लेन-देन आपको यहां ज्यादा मदद नहीं करते … जब तक कि आप एकाधिक HTTP अनुरोधों (जो आपको सबसे ज्यादा नहीं चाहते हैं) पर लेनदेन चलाना चाहते हैं।

हम उन मामलों में आमतौर पर क्या उपयोग करते हैं "आशावादी लॉकिंग" जेगो ओआरएम उस समर्थन का समर्थन नहीं करता है जहां तक ​​मुझे पता है। लेकिन इस सुविधा को जोड़ने के बारे में कुछ चर्चा हुई है।

तो आप अपने दम पर हैं असल में, आपको क्या करना चाहिए अपने मॉडल में एक "संस्करण" फ़ील्ड जोड़ना है और उसे छिपे हुए फ़ील्ड के रूप में उपयोगकर्ता को पास करना होगा एक अद्यतन के लिए सामान्य चक्र है:

  1. डेटा पढ़ो और उपयोगकर्ता को इसे दिखाएं
  2. उपयोगकर्ता डेटा संशोधित करें
  3. उपयोगकर्ता डेटा पोस्ट करें
  4. ऐप उसे डेटाबेस में वापस बचाता है।

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

आप ऐसा कुछ के साथ एक एकल SQL कॉल के साथ कर सकते हैं:

 UPDATE ... WHERE version = 'version_from_user'; 

यह कॉल केवल डेटाबेस को अपडेट करेगा, यदि संस्करण अभी भी वही है।

Django 1.11 में आपके व्यापार तर्क की आवश्यकताओं के आधार पर इस स्थिति को संभालने के लिए तीन सुविधाजनक विकल्प हैं:

  • Something.objects.select_for_update() जब तक मॉडल मुक्त नहीं हो जाता तब तक ब्लॉक होगा
  • Something.objects.select_for_update(nowait=True) और DatabaseError Something.objects.select_for_update(nowait=True) पकड़ते हैं यदि मॉडल वर्तमान में अद्यतन के लिए लॉक है
  • Something.objects.select_for_update(skip_locked=True) वर्तमान में लॉक किए गए ऑब्जेक्ट वापस नहीं करेगा

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

अनुक्रमिक बैच प्रक्रियाओं में "प्रतीक्षा" select_for_update बहुत सुविधाजनक है – मैं उन सभी को निष्पादित करने के लिए चाहता हूं, लेकिन उन्हें अपना समय दें nowait का प्रयोग किया जाता है जब कोई उपयोगकर्ता अद्यतन करने के लिए लॉक किए गए किसी ऑब्जेक्ट को संशोधित करना चाहता है – मैं उसे बताता हूं कि इस समय इसे संशोधित किया जा रहा है।

skip_locked किसी अन्य प्रकार के अपडेट के लिए उपयोगी है, जब उपयोगकर्ता किसी ऑब्जेक्ट के skip_locked स्कैन कर सकते हैं – और मुझे यह परवाह नहीं है कि जब तक यह ट्रिगर हो जाए, तब तक skip_locked मुझे चुपचाप डुप्लिकेट ट्रिगर्स को छोड़ने की अनुमति देता है

भविष्य के संदर्भ के लिए, https://github.com/RobCombs/django-locking देखें । यह एक तरह से ताला लगाता है कि उपयोगकर्ता अनजाने तालों को नहीं छोड़ता है, जब जावास्क्रिप्ट अनलॉकिंग का मिश्रण होता है जब उपयोगकर्ता पृष्ठ को छोड़ देता है, और लॉक टाइमआउट (जैसे उपयोगकर्ता के ब्राउज़र क्रैश होने पर)। दस्तावेज़ीकरण बहुत पूर्ण है।

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

कई प्रयोक्ताओं को एक ही डेटा का संपादन करने की आपकी वास्तविक समस्या के रूप में … हाँ, लॉकिंग का उपयोग करें या:

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

एक डीजेंगो ऐप / लाइब्रेरी बहुत संभावना है जो आपके लिए यह बहुत अधिक है।

एक और चीज की तलाश है जो "परमाणु" शब्द है एक परमाणु आपरेशन का मतलब है कि आपका डेटाबेस परिवर्तन सफलतापूर्वक होगा, या स्पष्ट रूप से विफल हो जाएगा। एक त्वरित खोज से पता चलता है कि Django में परमाणु आपरेशनों के बारे में सवाल है ।

ऊपर विचार

 updated = Entry.objects.filter(Q(id=e.id) && Q(version=e.version))\ .update(updated_field=new_value, version=e.version+1) if not updated: raise ConcurrentModificationException() 

बहुत अच्छा लग रहा है और बिना सीरिज योग्य लेनदेन के भी ठीक काम करना चाहिए।

समस्या यह है कि बहिरेब को कैसे बढ़ाएं। Save () व्यवहार के रूप में मैन्युअल पाइपलाइन को नहीं करना है .update () विधि को कॉल करने के लिए।

मैंने कस्टम प्रबंधक विचार को देखा

मेरी योजना अद्यतन करने के लिए Model.save_base () द्वारा प्रबंधक _update विधि को ओवरराइड करना है।

यह Django 1.3 में वर्तमान कोड है

 def _update(self, values, **kwargs): return self.get_query_set()._update(values, **kwargs) 

आईएमएचओ को क्या करने की जरूरत है:

 def _update(self, values, **kwargs): #TODO Get version field value v = self.get_version_field_value(values[0]) return self.get_query_set().filter(Q(version=v))._update(values, **kwargs) 

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

यह अजीब है कि जेडेंजो जैसे मॉडरेटर उपकरण ऑप्टिमास्टिक कॉनक्यूरेंसिस कंट्रोल के लिए मार्गदर्शन का अभाव है।

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

सुरक्षित होने के लिए डेटाबेस को लेनदेन का समर्थन करने की आवश्यकता है

अगर खेतों "फ्री-फॉर्म" जैसे पाठ आदि हैं और आपको कई प्रयोक्ताओं को उसी फ़ील्ड को संपादित करने में सक्षम होने की आवश्यकता है (आप डेटा के लिए एकल उपयोगकर्ता स्वामित्व नहीं प्राप्त कर सकते हैं), तो आप मूल डेटा को एक में संग्रहीत कर सकते हैं चर। जब उपयोगकर्ता बिगड़ता है, तो जांचें कि क्या इनपुट डेटा मूल डेटा से बदल गया है (यदि नहीं, तो पुराने डेटा को दोबारा लिखकर डीबी को परेशान करने की आवश्यकता नहीं है), अगर डीबी में वर्तमान डेटा की तुलना में मूल डेटा समान है आप सहेज सकते हैं, यदि यह बदल गया है तो आप उपयोगकर्ता को अंतर दिखा सकते हैं और उपयोगकर्ता को क्या करना है यह पूछ सकते हैं।

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

मुझे डीजेंगो नहीं पता है, इसलिए मैं आपको सीडी 3 एस नहीं दे सकता ..;)

यहां से:
किसी ऑब्जेक्ट को ओवरराइट करने के लिए कैसे करें

मैं मान रहा हूँ कि टाइमस्टैम्प को छिपे हुए फ़ील्ड के रूप में रखा जाएगा, जिसमें आप विवरणों को सहेजने की कोशिश कर रहे हैं।

 def save(self): if(self.id): foo = Foo.objects.get(pk=self.id) if(foo.timestamp > self.timestamp): raise Exception, "trying to save outdated Foo" super(Foo, self).save()