【问题标题】:PHP, mysqli, and table locks?PHP、mysqli 和表锁?
【发布时间】:2009-10-16 19:35:48
【问题描述】:

我有一个数据库表,我需要在其中提取一行,测试用户输入是否匹配,然后更新该行以识别进行匹配的用户。如果出现竞争情况,我需要确保第一个用户的更新不会被另一个用户覆盖。

为此,我打算:
1. 读取行
2.锁表
3. 再次读取行并与原始行进行比较
4.如果行匹配更新,否则什么都不做(另一个用户已经更新了行)

根据我在 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 连接,我用它来在数据库上执行准备好的语句。

当我运行我的测试脚本时,我会启动第一个用户并等待 "Stalling to allow for conflict..." ,然后启动第二个脚本。在第二个脚本中,我预计它会在“锁定...”处阻止,但是,第二个脚本也继续“停止以允许冲突...”。

由于 LOCK 语句似乎没有阻塞,也没有返回任何获取锁的指示符(返回值是回显和空白),我不清楚我实际上是在获取锁。即使我是,我也不知道该怎么做。

任何指针?

【问题讨论】:

    标签: php mysqli locking


    【解决方案1】:

    疑难解答:您可以通过尝试使用另一个未锁定的表来测试表锁定是否成功。如果您获得了锁,尝试写入未包含在锁语句中的表应该会产生错误。

    您可能需要考虑另一种解决方案。代替锁定,执行包含已更改元素作为 where 子句的一部分的更新。如果您正在更改的数据在您读取后发生了更改,则更新将“失败”并返回零行已修改。这消除了表锁,以及它可能带来的所有混乱恐怖,包括死锁。

    【讨论】:

    • 谢谢查尔斯!使用 where 子句完全避免锁定效果很好。
    猜你喜欢
    • 1970-01-01
    • 2021-02-11
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    • 2014-10-30
    • 2016-01-14
    • 1970-01-01
    相关资源
    最近更新 更多