phs

2012-03-21 18 views
6

के माध्यम से mysql पंक्ति लॉकिंग मैं अपने व्यापार के लिए एक वेब आधारित फॉर्म के साथ एक दोस्त की मदद कर रहा हूं। मैं इसे एकाधिक उपयोगकर्ताओं को संभालने के लिए तैयार करने की कोशिश कर रहा हूं। मैंने इसे सेट अप किया है ताकि संपादन के लिए रिकॉर्ड प्रदर्शित होने से ठीक पहले मैं निम्नलिखित कोड के साथ रिकॉर्ड लॉक कर रहा हूं।phs

$query = "START TRANSACTION;"; 
mysql_query($query); 
$query = "SELECT field FROM table WHERE ID = \"$value\" FOR UPDATE;"; 
mysql_query($query); 

(ठीक है कि बहुत सरल है लेकिन यह है कि mysql का सार है)

यह काम किया जाना प्रतीत नहीं होता है। हालांकि, जब मैं कमांड लाइन से mysql पर सीधे जाने, एक ही उपयोगकर्ता से लॉग इन और निष्पादित

START TRANSACTION; 
SELECT field FROM table WHERE ID = "40" FOR UPDATE; 

मैं प्रभावी रूप से वेब फार्म तक पहुँचने रिकॉर्ड "40" से ब्लॉक कर सकते हैं और समय समाप्ति चेतावनी मिलती है।

मैंने स्टार्ट ट्रांज़ेक्शन के बजाय BEGIN का उपयोग करने का प्रयास किया है। मैंने पहले SET AUTOCOMMIT = 0 करने और लॉकिंग के बाद लेनदेन शुरू करने का प्रयास किया है, लेकिन मैं PHP कोड से पंक्ति को लॉक नहीं कर सकता। चूंकि मैं कमांड लाइन से पंक्ति को लॉक कर सकता हूं, मुझे नहीं लगता कि डेटाबेस कैसे स्थापित किया गया है इसके साथ कोई समस्या है। मैं वास्तव में उम्मीद कर रहा हूं कि कुछ आसान कुछ है जो मैंने अपने पढ़ने में चूक गए हैं।

एफवाईआई, मैं एक्सएएमपीपी संस्करण 1.7.3 पर विकास कर रहा हूं जिसमें अपाचे 2.2.14, MySQL 5.1.41 और PHP 5.3.1 है।

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

+0

आपने दूसरे mysql_query ($ query) के बाद क्या किया; ?अगर आपकी PHP स्क्रिप्ट बाहर निकलें, तो – PasteBT

उत्तर

0

इस के लिए पीडीओ का उपयोग करें (और सभी डेटाबेस कार्यों):

$value = 40; 

try { 
    $dbh = new PDO("mysql:host=localhost;dbname=dbname", 'username', 'password'); 
} catch (PDOException $e) { 
    die('Could not connect to database.'); 
} 

$dbh->beginTransaction(); 

try { 
    $stm = $dbh->prepare("SELECT field FROM table WHERE ID = ? FOR UPDATE"); 
    $stm->execute(array($value)); 
    $dbh->commit(); 
} catch (PDOException $e) { 
    $dbh->rollBack(); 
} 

आप प्राचीन mysql_ उपयोग करना आवश्यक है * कार्यों आप कर सकते हैं की तरह कुछ:

mysql_query('SET AUTOCOMMIT=0'); 
mysql_query('START TRANSACTION'); 
mysql_query($sql); 
mysql_query('SET AUTOCOMMIT=1'); 
+2

रिलीज लॉक करें मौन में डाउनवोट न करें। बेहतर उत्तरों की मदद के लिए एक टिप्पणी छोड़ दो। – webbiedave

+2

रिकॉर्ड के लिए मुझे इस सुझाव के साथ कोई समस्या नहीं है, यह आगे सोच रहा है! – Paul

0

समस्या mysql आदेशों हैं। आप इस

http://nz.php.net/manual/en/class.mysqli.php

या पीडीओ के लिए mysqli इस्तेमाल कर सकते हैं। यहाँ वर्णित:

PHP + MySQL transactions examples

HTH

+0

मैं webbiedave से सहमत हूं। कृपया मुझे बताएं कि आपने ऐसा क्यों किया और कैसे सुधार किया जाए, इससे आपको और समुदाय की मदद मिलेगी। धन्यवाद! – Andreas

0

आप mysql एपीआई यह गलतियों कि सक्षम बनाता है एसक्यूएल-इंजेक्शन और इस तरह है, साथ ही यह कुछ कार्यक्षमता नहीं करना आसान है क्योंकि उपयोग नहीं करना चाहिए। मुझे संदेह है कि लेनदेन इनमें से एक है क्योंकि यदि मैं गलत नहीं हूं तो हर प्रश्न "स्वयं द्वारा" भेजा जाता है और बड़े संदर्भ में नहीं।

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

लेनदेन की कार्यक्षमता के लिए झूठी पर स्वत: प्रतिबद्धता सेट करें और जब आप इसे चाहते हैं तो स्वयं को प्रतिबद्ध करें। यह लेनदेन शुरू करने और रोकने के समान ही है।

पर संदर्भ देखने के लिए:

http://www.php.net/manual/en/mysqli.autocommit.php

http://www.php.net/manual/en/mysqli.commit.php

9

समस्या अपने कोड की वाक्य रचना नहीं है, लेकिन जिस तरह से आप इसका इस्तेमाल करने की कोशिश कर रहे हैं।

बस से पहले रिकॉर्ड संपादन मैं निम्नलिखित कोड

इस मुझे लगता है कि आप चुन सकते हैं और यह सोचते हैं रहा से साथ रिकॉर्ड ताला लगा रहा प्रदर्शित किया जाता है "ताला" पंक्ति, तो है कि संपादित करें पृष्ठ प्रदर्शित आपका उपयोगकर्ता, तब जब वे परिवर्तन जमा करते हैं तो यह तालिका को सहेजता है और "अनलॉक करता है"। यहां मूलभूत समस्या निहित है। जब आपका पृष्ठ लोड हो रहा है, तो PHP MySQL कनेक्शन से बाहर निकलता है और बंद करता है। जब ऐसा होता है, तो सभी ताले तुरंत जारी किए जाते हैं। यही कारण है कि कंसोल आपके PHP से भिन्न व्यवहार करता प्रतीत होता है। कंसोल में समकक्ष आप प्रोग्राम से बाहर निकलेंगे।

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

एक और परिदृश्य है जो किसी समस्या का कारण बन सकता है। यदि उपयोगकर्ता संपादन के लिए एक रिकॉर्ड खोलता है, तो ब्राउज़र को सहेजने या रद्द करने के बिना बंद कर देता है, संपादन लॉक हमेशा के लिए हमेशा के लिए रहेगा। यही कारण है कि मैंने कहा कि इसे बंद कर दिया गया समय स्टोर करें। संपादक को खुद को हर 2 मिनट या तो एजेक्स कॉल करना चाहिए ताकि "मुझे अभी भी ताला की जरूरत है!"। जब PHP प्रोग्राम को यह "रिलेक" अनुरोध प्राप्त होता है, तो उसे लॉक की खोज करनी चाहिए, फिर वर्तमान में टाइमस्टैम्प अपडेट करें। इस तरह लॉक पर टाइमस्टैम्प हमेशा 2 मिनट के भीतर अद्यतित है। पुराने पुराने ताले को हटाने के लिए आपको एक और प्रोग्राम बनाने की भी आवश्यकता है। यह हर कुछ मिनट में एक क्रॉन नौकरी में चलना चाहिए। इसे किसी भी ताले के लिए 5 मिनट से अधिक समय के साथ टाइमस्टैम्प के साथ खोजना चाहिए, और हटा दें। यदि टाइमस्टैम्प उस से बड़ा है, तो स्पष्ट रूप से संपादक कुछ करीब था या टाइमस्टैम्प 2 मिनट के भीतर अद्यतित होगा।

जैसा कि कुछ अन्य लोगों ने उल्लेख किया है, आपको mysqli का उपयोग करने का प्रयास करना चाहिए। यह "MySQL सुधारित" है और पुराने इंटरफ़ेस के प्रतिस्थापन है।

+0

ऐसा करने का यह तरीका कुछ फायदे हैं लेकिन कुछ नुकसान भी हैं। आपको समय-समय पर अपने लॉक/अनलॉक टेबल के लिए क्लीनअप की आवश्यकता होगी। यह दुर्घटनाओं या अप्रत्याशित व्यवधान के कारण होता है। मैं व्यक्तिगत रूप से इसका उपयोग नहीं करता। – Andreas

+0

ठीक है जेमैक, आपने अभी अपना जवाब बढ़ाया है और आपके दूसरे भाग में नुकसान समझाया है। ठोस उत्तर +1 – Andreas

+0

@Andreas मेरे विवरण में शामिल है लॉक टेबल को साफ़ करने का एक तरीका है ताकि कोई भी ब्राउज़र क्रैश कुछ मिनटों से रिकॉर्ड लॉकआउट का कारण बन सके। –

0

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

UPDATE table 
SET LockTime='$now',LockedBy='$Userid' 
WHERE Key='$value' AND (LockTime IS NULL OR LockTime<'$past' OR LockedBy='$Userid') 

($ पिछले 4 मिनट पहले है) इस विफल रहता है, किसी और ताला है। इस प्रकार मैं स्पष्ट रूप से अनलॉक कर सकते हैं या अपनी लॉक समाप्त कर देते:

UPDATE table 
SET LockTime=NULL,LockedBy='' 
WHERE Key='$value' AND LockedBy='$Userid' 

एक क्रॉन जॉब वर्ष ताले को दूर कर सकता है, लेकिन यह वास्तव में आवश्यक नहीं है।