php - एक साथ डीबी तालिका पंक्ति पहुंच को रोकना



mysql timestamp (3)

यह कभी-कभी ऐसा होता है कि हमारी सहायता टीम में दो व्यवस्थापक डीबी तालिका पंक्ति पर एक समान संवेदनशील ऑपरेशन करने की कोशिश कर रहे हैं (मान लें, पंक्ति में मान को संशोधित करना) हमें इसे रोकने की जरूरत है। (रोब लॉकिंग संभव नहीं है क्योंकि टेबल "मिसाम" हैं)

मैंने कई समाधानों के बारे में सोचा है:

फॉर्म में पुरानी मान की स्थापना और प्रस्तुत करने के साथ मौजूदा एक के साथ इसकी तुलना करें

   <input name="money"><input type="hidden" name="old_money" value="10">

और फिर अपडेट करने से पहले:

   $currentmoney=value_from_query("select money from mytable","money");
   if($currentmoney!=$_REQUEST["old_money"]){
      return "value changed to $currentmoney while you were editing it, are you sure you still want to change it?!??!?!?!?";
   }
   else{
     mysql_query("update everyonesmoney set money='".intval($_REQUEST["money"])."' where user='$user_id'");
     return true;
   }

लेकिन निम्नलिखित स्थिति हो सकती है:

  1. उपयोगकर्ता को 9 डॉलर से 10 डॉलर तक परिवर्तित होने के लिए धन मूल्य की आवश्यकता है

  2. admin1 10 डॉलर में अपने पैसे बदलता है

  3. उपयोगकर्ता चालाकी से 1 डॉलर खर्च करता है, इसलिए उसका वर्तमान पैसा 9 डॉलर फिर से हो जाता है!

  4. admin2 कोई चेतावनी नहीं के साथ 10 $ अपने पैसे बदलता है

पंक्ति में टाइमस्टैम्प (updated_at कॉलम) सेटिंग बनाना

और समाधान 1 में भी ऐसा ही करना है। इसका लाभ यह है कि यह सरल डेटा तुलना से ज्यादा कह रहा है हम यह सुनिश्चित करने के लिए कह सकते हैं कि डेटा बदल दिया गया था जब हम फॉर्म के साथ नगण्य थे या नहीं नुकसान - हम ट्रैक नहीं कर सकते हैं कि कौन सी कॉलम बिल्कुल बदल गया था, जब तक कि हम इसे हल 1 के साथ नहीं जोड़ते

   <input type="hidden" name="formtimestamp" value="<? echo time();?>">

और फिर अद्यतन करते समय:

   $query_add = ($overriden ? "" : " and updated_at>'".securevalue($_REQUEST["formtimestamp"])."'");
   if(mysql_affected_rows(mysql_query("update everyonesmoney set money='".intval($_REQUEST["money"])."', updated_at=NOW() where user='$user_id' ".$query_add))==0){
      return "some values were changed by someone else while you were editing it, are you sure you still want to change it?!??!?!?!?";
   }
   else{
     return true;
   }

ऑब्जेक्ट / एक्शन-विशिष्ट नाम के साथ अस्थायी 0-लंबाई फ़ाइल बनाना

अपडेट के दौरान इसे बनाकर / लॉक करना, और अपडेट के पहले अपने अस्तित्व / डेटास्टैम्प की जांच करना।

अद्यतन करने से पहले:

   $myfname="/tmp/user{$user_id}EDITMONEY.tmp";
   $timedifference=((time()-filectime($myfname)); //in seconds
   if(file_exists($myfname) and ($timedifference<60) and (!$overriden)){ // a minute difference
      $currentmoney=value_from_query("select money from mytable","money");
      return "money were edited by someone else $timedifference seconds ago and set to {$currentmoney}, are you sure you still want to change it?!??!?!?!?";
   }else{
      $fp = fopen("/tmp/user".intval($_REQUEST["user_id"])."EDITMONEY.tmp", "r+");         
      if (flock($fp, LOCK_EX)) { // do an exclusive lock
         mysql_query("update everyonesmoney set money='".intval($_REQUEST["money"])."' where user='$user_id'")
        flock($fp, LOCK_UN); // release the lock
        return true;
     } else {
        return "Couldn't get the lock, it's possible that someone tried to execute query simultaneously!";
     }

   fclose($fp);

   }

अब फ़ाइल निर्माण मेरा पसंदीदा दृष्टिकोण है क्योंकि:

  1. मुझे लगता है कि एक्सेस डेटाबेस से स्थानीय फाइल बनाने में तेज़ है।

  2. मुझे तालिका में एक और स्तंभ (टाइमस्टैम्प) जोड़ने की आवश्यकता नहीं है I

  3. मैं विशिष्ट कॉलम संशोधनों की जांच करने के लिए फ़ाइल नाम को आसानी से संशोधित कर सकता हूं, यानी फ़ाइल "money_user {$ userid} _modified" बनाने के लिए जब mysqlupdate किया जाता है।

क्या यह सही है या क्या कुछ गलत है?


Answer #1

InnoDB और लेनदेन को देखें वे संवेदनशील परिवर्तनों (यानी शेष) के लिए अधिक उपयुक्त हैं।

डेटाबेस आमतौर पर बेहतर होते हैं क्योंकि वे एक केंद्रीकृत समाधान होते हैं। अगर आपको यातायात या सामान्य तौर पर लोड करने के कारण स्केल करना है, तो उन फ़ाइलों को समन्वय करना आसान नहीं है जब तक आपको स्केलिंग और आई / ओ दरों की कोई ज़रूरत नहीं है, यह ठीक नहीं है।

मुझे 2 संभावित समाधानों का उल्लेख करने की अनुमति दें, जिन्हें आपने ऊपर उल्लिखित किया हो।

आप अपने व्यवस्थापक खाते के आईडी के साथ एक "assigned_id" जोड़ सकते हैं, ताकि टाइमस्टैम्प के साथ मिलाया जा सके ताकि आपका एप्लिकेशन एक चेतावनी दिखाए यदि कोई अन्य इसे संपादित कर रहा है।

एक अन्य संभावित समाधान यह है कि आप अपने फॉर्म भरते समय कोई परिवर्तन किए गए हैं या नहीं। एक अंतिम समयबद्ध टाइमस्टैम्प का उपयोग यहां किया जा सकता है।


Answer #2

आप UPDATE ऑपरेशन के WHERE खंड में पुराना मान निर्दिष्ट कर सकते हैं, और फिर प्रभावित पंक्तियों की संख्या को देखें:

दिया हुआ

id  name          amount
--- ------------- ---------
1   Joe User      10

थ्रेड 1 चलाता है

UPDATE accounts SET amount=9 WHERE id=1 AND amount=10;
=> Query Okay, 1 row(s) affected

धागा 2 निष्पादित

UPDATE accounts SET amount=9 WHERE id=1 AND amount=10;
=> Query Okay, 0 row(s) affected

इसके अलावा, मैं व्यतीत समय की मात्रा को कम करने के लिए, सबसे पहले व्यक्तिगत व्यवस्थापक को कार्य सौंपने के बाद, संभवतः थोड़ी देर में बहिष्कार को लागू कर सकता था।


Answer #3

मुझे लगता है कि डेटाबेस की पंक्ति-स्तरीय लॉकिंग ऐसी स्थिति को पूरा नहीं करती जो आपने पहली विधि में उल्लिखित की थी। लेकिन मुझे नहीं लगता कि फ़ाइल निर्माण डाटाबेस सिस्टम तक पहुंचने में तेज़ है, न ही फ़ाइल निर्माण डाटाबेस पर सीआरयूडी की तुलना में स्पष्ट रूप से भारी है।

इसलिए, मैं लॉगिंग तालिका के साथ एक समान दृष्टिकोण सुझाता हूं।

  • प्रत्येक तालिका की अपनी प्राथमिक कुंजी है (जैसे pid )
  • तालिका नाम और पिन को टाइमस्टैम्प के साथ लॉग टेबल में रिकॉर्ड करें, जब कोई किसी पंक्ति को बेधने का प्रयास करे
  • एक क्वेरी चलाने से पहले लॉग तालिका की जाँच करें




simultaneous