2012-06-29 12 views
6

मुझे सिद्धांत के साथ एक पूरी तालिका (एक पंक्ति नहीं) को लॉक करने की आवश्यकता है, यदि संभव हो तो मैं मूल प्रश्नों के बिना ऐसा करना चाहता हूं।doctrine2 के साथ symfony2 में एक पूरी तालिका को कैसे लॉक करें?

pessimistic locking के लिए दस्तावेज़ केवल बताता है कि कैसे इन तरीकों के माध्यम से विशिष्ट संस्थाओं लॉक करने के लिए:

  • EntityManager #
  • EntityManager # ताला
  • क्वेरी # setLockMode

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

मैं स्पष्ट लेनदेन सीमांकन का उपयोग कर रहा हूं, जिसे लॉकिंग के साथ अच्छी तरह से काम करना चाहिए (ऊपर दिए गए दस्तावेज के अनुसार)।

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

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

मैं इस समस्या का सामान्य समाधान ढूंढ रहा हूं, जब auto_increment अच्छा नहीं है, उदाहरण के लिए स्ट्रिंग्स, या एकाधिक कॉलम, हैंश या पिछले पंक्ति सेट पर जो भी गणना करना है, उसके साथ।

लॉकिंग एक ठोस समाधान है और आशावादी लॉकिंग के विपरीत, आपको त्रुटियों पर पुनः प्रयास करने की आवश्यकता नहीं है।

तो, क्या सिद्धांत में टेबल लॉकिंग का उपयोग करने का कोई तरीका है?

+0

इमो बनाने के लिए आवश्यक किया गया था, एक बेहतर विकल्प एक सौदे को खोलने के लिए होगा: एक देशी अद्यतन का उपयोग करना मेरे लिए समस्या तय एक चयनित क्वेरी के माध्यम से आपको आवश्यक तालिका से डेटा प्राप्त करें, और फिर अद्यतन करें। – JamesHalsall

+0

समस्या यह है कि यदि दूसरा लेनदेन पहले होता है तो पहले लेनदेन एक अवैध मूल्य डालेगा। दूसरे लेनदेन का नतीजा पहले भी द्वारा डाली गई पंक्ति पर निर्भर होना चाहिए। यही कारण है कि मुझे लॉकिंग की आवश्यकता है, लेन-देन उस तालिका के लिए ओवरलैप नहीं होना चाहिए। – Jens

उत्तर

1

सिद्धांत 2.x में प्रलेखन को देखने से मुझे नहीं लगता कि पूरी तालिका को लॉक करने का एक समर्थित तरीका है। आप निश्चित रूप से सिद्धांत के माध्यम से सभी रिकॉर्ड लॉक करने का प्रयास कर सकते हैं, लेकिन यह बोझिल होगा और वास्तव में एक अच्छा विचार नहीं है।

इसके बजाय, मैं डेटाबेस पर कच्चे एसक्यूएल निष्पादित करने के लिए ...

$em->getConnection()->exec('LOCK TABLES table_name WRITE;'); //lock for write access

और सिद्धांत इकाई प्रबंधक का प्रयोग करेंगे तो आप अपने अद्यतन के साथ काम हो गया के बाद ...

$em->getConnection()->exec('UNLOCK TABLES;');

संपादित करें:

तालिका ताले पर MySQL documentation से

...

  • सत्र कि ताला पढ़ सकते हैं और तालिका में लिख सकते हैं रखती है।

  • केवल सत्र जो लॉक रखता है, तालिका तक पहुंच सकता है।लॉक जारी होने तक कोई अन्य सत्र इसका उपयोग नहीं कर सकता है।

  • WRITE लॉक होने पर अन्य सत्र ब्लॉक द्वारा तालिका के लिए अनुरोध लॉक करें।

मुझे लगता है कि यहां दूसरी बात महत्वपूर्ण है, केवल आपके सत्र/लिखने कि मेज पर पढ़ सकते हैं।

try { 
    $entity = $em->find('User', $theEntityId, LockMode::OPTIMISTIC, $expectedVersion); 

    // do the work 

    $em->flush(); 
} catch(OptimisticLockException $e) { 
    echo "Sorry, but someone else has already changed this entity. Please apply the changes again!"; 
} 

LockMode :: आशावादी पैरामीटर प्रदान कर सकते हैं कि तुम क्या जरूरत है:

+0

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

+0

'लॉक टैबलेट [tbl_name] 'लेखन के लिए पूरी तालिका को लॉक कर देगा, मेरा संपादन – JamesHalsall

+0

देखें, मुझे पता है, मेरे पास LOCK के साथ एकमात्र समस्या यह है कि जब आप' autocommit = 0 'का उपयोग करके लेनदेन करते हैं तो यह केवल तभी अच्छा होता है, और मैं मुझे यकीन नहीं है कि सिद्धांत कैसे लेनदेन को संभालता है। मुझे अभी भी इसका परीक्षण करना है। यह http://dev.mysql.com/doc/refman/5.0/en/lock-tables-and-transactions.html – Jens

1

संभवतः द्वारा Doctrine2 ORM select for update

दोहराया यहाँ कुछ संबंधित कोड है।

$em->getConnection()->exec('LOCK TABLES table_name WRITE;'); //lock for write access 

// calculate $new_number... 

// persist $new_number on table_name... 
$table_name->setCalculatedNumber($new_number); 
$em->persist($table_name); 
$em->flush(); 

$em->getConnection()->exec('UNLOCK TABLES;'); 

मैं JMeter साथ यह परीक्षण किया है, और ताला एक भारी बोझ (16 अनुरोधों/सेक) के साथ काम नहीं कर रहा था:

+0

सामान्य रूप से, अद्यतन के लिए पंक्ति का चयन समवर्ती आवेषण को रोकता नहीं है। –

2

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

$em->getConnection()->exec('LOCK TABLES table_name WRITE;'); //lock for write access 

// calculate $new_number... 

// persist $new_number on table_name... 
$em->getConnection()->executeUpdate("UPDATE table_name set ...;");  

$em->getConnection()->exec('UNLOCK TABLES;'); 
$em->refresh($table_name); 

अनुगामी ताज़ा() गणना की संख्या बाद में क्वेरी में उपलब्ध परिणाम