我设计了一个网站显示书籍出租使用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之后,您需要回读记录以检查是否成功地"保留"了它。这样,只有一个更新通过。