【问题标题】:How to deal with tons of simultaneous UPDATE request to one record in mySQL database and determine who arrived first如何处理对 mySQL 数据库中一条记录的大量同时更新请求并确定谁先到达
【发布时间】:2011-07-28 16:28:33
【问题描述】:

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

MySQL 表:

图书(book_ID, title, current_user, expire_time)

一个。当用户点击书籍时:PHP 检查 expire_time

b.如果为 true(之前的查看时间已过期),请将 current_user 字段设置为请求者的用户 ID,并将过期时间设置为 now + 10 秒:

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

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

d。如果为真,则显示“借阅页面”。

e。如果为 false,则显示错误消息“其他人正在查看该书。请在 10 秒后回来”

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

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

【问题讨论】:

  • 听起来您正在尝试使用内置行锁定功能的衍生产品...
  • 听起来像是一个不错的比赛条件环境。您需要按照上面的建议使用锁。
  • 既然案例假设有 100 个不同的用户试图同时访问这本书,那么发出锁不会导致死锁吗?比方说每个人同时达到代码执行锁定命令,会发生什么?
  • 谁能给我举个例子,哪种锁最适合我的情况以及放置在哪里?谢谢

标签: php mysql request


【解决方案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;
        }

    }

【讨论】:

  • 谢谢 m1tk4,你的逻辑有道理!!感谢 Chris 详细说明。你们俩都摇滚! Thx 堆 =)
【解决方案2】:

您需要在 UPDATE 语句中添加对“图书已被使用”的检查。 IE。在您的 WHERE 子句中,除了 ID 外,还要检查 expire_time 是否已用完。在 UPDATE 之后,您需要回读记录以检查您是否成功“保留”了它。这样,只有一个更新通过。

【讨论】:

  • 谢谢 m1tk4,你的逻辑有道理!!感谢 Chris 详细说明。你们俩都摇滚! Thx 堆 =)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多