我有一个数据库表,我需要在其中提取一行,测试用户输入是否匹配,然后更新该行以识别进行匹配的用户。如果出现争用情况,我需要确保第一个用户的更新不会被另一个用户覆盖。
为了实现这一目标,我打算:
根据我在Google上找到的信息,我预计lock table语句会阻塞,直到获得锁为止。我在PHP中设置了一个小测试脚本,该脚本将暂停10秒,以便有时间手动创建竞态条件。
// attempt to increment the victor number
$aData["round_id"] = $DATABASE["round_id"];
// routine to execute a SELECT on database (ommited for brevity)
$aRound = $oRound->getInfo($aData);
echo "Initial Round Data:";
print_r($aRound);
echo "Locking...";
echo $oRound->lock();
echo "Stalling to allow for conflict...";
sleep(10);
echo "Awake...";
$aLockedRound = $oRound->getInfo($aData);
if($aRound["victor_nation"] == $aLockedRound["victor_nation"]){
$aData["victor_nation"] = $aRound["victor_nation"] + 1;
$oRound->update($aData);
echo "Incremented Victor Nation";
}其中,锁例程定义为
function lock(){
global $oDatabase;
$iReturn = 0;
// lock the table
$iReturn = $oDatabase->m_oConnection->query("LOCK TABLES round WRITE");
return $iReturn;
}上面,$oDatabase->m_oConnection是一个mysqli连接,我使用它在数据库上执行准备好的语句。
当我运行我的测试脚本时,我踢开第一个用户并等待“停止以允许冲突...”,然后启动第二个脚本。在第二个脚本上,我预计它会在“锁定...”处阻塞,然而,第二个脚本也继续“停止以允许冲突...”。
由于lock语句看起来没有阻塞,也没有返回任何获取锁的指示符(返回值是回显的且为空),所以我不清楚我实际上是不是在获取锁。即使我是,我也不确定该怎么做。
有什么建议吗?
发布于 2009-10-17 06:43:21
故障排除:您可以通过尝试使用另一个未锁定的表来测试表锁是否成功。如果您获得了锁,则尝试写入没有包含在lock语句中的表应该会生成错误。
您可能需要考虑另一种解决方案。在where子句中执行包含更改元素的更新,而不是锁定。如果正在更改的数据在读取后发生了更改,则更新将“失败”,并返回零行已修改。这就消除了表锁,以及所有随之而来的混乱的恐怖,包括死锁。
https://stackoverflow.com/questions/1579995
复制相似问题