如何处理对mySQL数据库中一条记录的大量同时更新请求,并确定谁先到达


How to deal with tons of simultaneous UPDATE request to one record in mySQL database and determine who arrived first

我设计了一个网站显示书籍出租使用php和mySQL。当有人点击这本书时,会显示一个带有倒计时计时器的信息页面,用户有10秒的时间来决定是否要借阅。如果时间到了,用户需要返回,再次点击图书,显示"借阅页面"。当用户单击该书时,PHP实际上首先检查该书当前是否正在被其他人"查看"。如果没有人查看,PHP显示"借阅页面",用户获得10秒的图书独占权。在这10秒内,其他用户无法打开页面或查看"借阅按钮"。一切都启动并运行,除了我不知道如何正确地做到这一点,所以只有一个用户可以得到10秒排他性首先。我的逻辑如下:

MySQL表:

Book(book_ID, title, current_user, expire_time)

。当用户点击图书时:PHP检查是否过期时间<现在()>

b。如果为真(先前的查看时间已过期),将current_user字段设置为请求者的userID,并将过期时间设置为现在+ 10秒:

UPDATE Book SET current_user='$userID', expire_time=ADDTIME(NOW(), '00:00:10')

c。如果为false(仍在查看时间内),则进一步检查current_user字段是否等于请求者的userID。

d。如果为true,则显示"借阅页面"。

e。如果为false,则显示错误MSG,提示"其他人正在查看该书"。请在10秒后回来"

我测试过用两台电脑同时点击这本书。大多数情况下,只有一台计算机可以访问该页面并获得10秒的独占性。然而,有一次两台电脑同时成功打开了"借书"页面。这绝对不是我想要的。想象一下,如果有100个web请求打开同一本书,其中一半通过,而只有1本书可供出租。

借书的事只是为了说明目的。我想知道的是,当有大量的查询同时到达mysql服务器时,如何获取或选择第一个,并将其余的搁置?

我将锁封装到一个类中,然后您可以这样做:

$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;
        }
    }

您需要在UPDATE语句中添加对"book already been taken"的检查。也就是说,在你的WHERE子句中,除了ID还检查expire_time是否已经用完。在UPDATE之后,您需要回读记录以检查是否成功地"保留"了它。这样,只有一个更新通过。