2011-07-28 2 views
3

phpとmySQLを使用して賃貸用の書籍を表示するWebサイトを設計しました。誰かが本をクリックすると、カウントダウンタイマー付きの情報ページが表示され、ユーザーは10秒以内に借りたいかどうかを判断できます。時間が経過している場合、ユーザーは元に戻ってブックを再度クリックして、「ページを借りる」を表示する必要があります。ユーザが書籍をクリックすると、PHPは実際にその本が現在他の誰かが閲覧しているかどうかを最初に確認します。誰もそれを見ていない場合、PHPは「ページを借りる」と表示し、ユーザは書籍に対して10秒の独占権を得る。この10秒間に、他のユーザーはページを開いたり、「借りボタン」を表示したりすることはできません。私はそれを正しく行う方法がわからないことを除いて、すべてが稼動しているので、ちょうど1人のユーザーが10秒の独占権を最初に得ることができます。次のように私のロジックは次のとおりです。複数の同時UPDATE要求をmySQLデータベースの1つのレコードに対処し、誰が最初に到着したかを決定する方法

MySQLのテーブル:

ブック(book_ID、タイトル、CURRENT_USER、expire_time)

。ユーザーがブックをクリックしたとき:PHP expire_timeがチェックされていないかチェックする。< NOW()

b。 true(以前の視聴時間が経過している)の場合、current_userフィールドをリクエスタのuserIDに設定し、有効期限を今すぐ+10秒に設定します。

UPDATE予約セットcurrent_user = '$ userID'、expire_time = ADDTIME(NOW() 00:00:10 ')

c。 false(まだ視聴時間内)の場合は、さらにcurrent_userフィールドがリクエスタのuserIDと等しいかどうかを確認します。

d。 trueの場合は、「ボローページ」を表示します。

e。偽の場合は、「他の誰かが現在本を見ています.10秒後に戻ってください」というエラーメッセージを表示します。

2台のコンピュータを使って本を同時にクリックしてテストしました。ほとんどの場合、1台のコンピュータだけがページにアクセスし、10秒間排他性を得ることができます。しかし、両方のコンピュータが同時に「借用ブック」ページを正常に開く時間があった。これは間違いなく私が望むものではありません。同じ本を開こうとするWebリクエストが100件あり、そのうちの半分が通っている間に1つの書籍しか貸していないとしたら、

書籍を借りるのは説明のためのものです。私が知りたいことは、同時にたくさんのクエリがmysqlサーバに到着したときに、最初のものを取得または選択して残りを保留にする方法です。

+1

はね... –

+0

はのような音素晴らしいレースコンディション環境上記のようにロックを使用する必要があります。 –

+0

このケースでは、100人の異なるユーザーが同時に書籍にアクセスしようとしているので、ロックを発行しないとデッドロックが発生する可能性がありますか?誰もが同時にロックコマンドを実行するコードに達すると、何が起こるでしょうか? – Albert

答えて

1

私は、あなたがこれを行うことができ、クラスにロックをカプセル化します:あなたは機能をロックするビルトイン行スピンオフを使用しようとしているよう

$book = new Book($book_id); 
$success = $book->getLock($user_id); 
if (!$success) 
    echo 'Lock failed'; 
else 
    echo 'You got 10 seconds to buy, sucka!'; 


    class book { 
     private $id = false; 
     private $initialized = false; 
     public function __construct($id = false) { 
      if (!is_numeric($id) || $id === false) 
       return false; 
        $this->id = $id; 
      $this->initialized = true; 
      return; 
     } 
     public function getLock($userID = false) { 
      if ($this->initialized !== true) 
       return false; 

      if (!is_numeric($userID) || $userID === false) 
       return false; 

      // check for a current lock 
      $sql = 'SELECT current_user, expire_time FROM Book WHERE id = '.$this->id; 

      // do whatever you do, get back the row 
      $avail = do_query($sql); 

      // the book is already locked 
      if ($avail['current_user'] > 0 && strtotime($avail['expire_time']) > time()) 
     return false; 

      // assert the lock 
      $sql = 'UPDATE Book SET current_user='.$userID.', expire_time=ADDTIME(NOW(), "00:00:10") WHERE id = '.$this->id; 

      // use whatever method you use for db access 
      do_query($sql); 

      // verify the lock 
      $sql = 'SELECT current_user FROM Book WHERE id = '.$this->id; 

      // do whatever you do for db access, get the id field 
      $result = do_query($sql); 

      // if these match, lock was a success 
      if ($result == $userID) 
       return true; 

      return false; 
     } 
     public function releaseLock($userID=false) { 
      if ($this->initialized !== true) 
       return false; 

      if (!is_numeric($userID) || $userID === false) 
       return false; 

      // verify the lock is in the specified user's id 
      $sql = 'SELECT current_user FROM Book WHERE id = '.$this->id; 

      // do whatever you do for db access, get the id field 
      $result = do_query($sql); 

      // if these match, lock is actively assigned to this user 
      if ($result == $userID) 
       return false; 

      // release it 
      $sql = 'UPDATE Book SET current_user=NULL, expire_time=NULL WHERE id = '.$this->id; 
      do_query($sql); 
      return true; 
     } 

    } 
+0

Thx m1tk4、あなたのロジックは理にかなっています!!それを精緻化するためのクリスThx。あなたは両方の岩! Thxヒープ=) – Albert

0

あなたのUPDATEステートメントには、「既に取っている本」のチェックを追加する必要があります。私。あなたのWHERE句では、IDに加えて、expire_timeがなくなったことをチェックします。 UPDATEの後、レコードを正常に「予約」したかどうかを確認するために、レコードを読み戻す必要があります。この方法で、あなたのアップデートのうちの1つだけがパスします。

+0

Thx m1tk4、あなたのロジックは理にかなっています!それを精緻化するためのクリスThx。あなたは両方の岩! Thxヒープ=) – Albert

関連する問題