mysql通过php锁定行

dee*_*zee 8 php mysql locking row

我正在帮助一位朋友使用基于网络的表格,这是为了他们的业务.我正准备让它准备好处理多个用户.我已经设置好了,因此在显示记录进行编辑之前,我使用以下代码锁定记录.

$query = "START TRANSACTION;";
mysql_query($query);
$query = "SELECT field FROM table WHERE ID = \"$value\" FOR UPDATE;";
mysql_query($query);
Run Code Online (Sandbox Code Playgroud)

(好吧,这是大大简化,但这是mysql的本质)

它似乎没有工作.但是,当我从命令行直接转到mysql时,使用相同的用户登录并执行

START TRANSACTION;
SELECT field FROM table WHERE ID = "40" FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)

我可以有效地阻止Web表单访问记录"40"并获得超时警告.

我尝试过使用BEGIN而不是START TRANSACTION.我已经尝试先执行SET AUTOCOMMIT = 0并在锁定后启动事务,但我似乎无法从PHP代码中锁定行.由于我可以从命令行锁定行,因此我认为数据库的设置方式不存在问题.我真的希望在阅读中我有一些简单的东西.

仅供参考,我正在开发XAMPP 1.7.3版本,其中包含Apache 2.2.14,MySQL 5.1.41和PHP 5.3.1.

提前致谢.这是我第一次发帖,但我过去从这个网站收集了很多知识.

Jor*_*ack 12

问题不在于代码的语法,而在于您尝试使用它的方式.

在显示记录进行编辑之前,我使用以下代码锁定记录

由此我假设您选择并"锁定"该行,然后将该编辑页面显示给您的用户,然后当他们提交更改时,它会保存并"解锁"该表.这里存在根本问题.当您的页面加载完成后,PHP退出并关闭MySQL连接.发生这种情况时,立即释放所有锁.这就是为什么控制台的行为似乎与PHP不同.控制台中的等价物是您退出程序.

您无法锁定表行以进行长时间的编辑.这不是他们的设计.如果要锁定记录以进行编辑,则需要在另一个表中跟踪这些锁.创建一个名为"edit_locks"的新表,并存储被锁定的记录ID,用户ID编辑以及锁定的时间.如果要打开记录进行编辑,请锁定整个edit_locks表,然后查询该记录是否被其他人锁定.如果不是,请插入锁定记录,如果是,则显示锁定错误.当用户保存或取消时,从edit_locks中删除锁定记录.如果你想让事情变得简单,只要你的程序想要使用它就可以锁定这个表.这将帮助您避免竞争条件.

还有一种情况可能会导致问题.如果用户打开记​​录进行编辑,然后关闭浏览器而不保存或取消,则编辑锁将永远保留在那里.这就是为什么我说存储它被锁定的时间.编辑器本身应每隔2分钟左右拨打一次AJAX电话,说"我还需要锁定!".当PHP程序收到此"重新锁定"请求时,它应该搜索锁,然后将时间戳更新为当前.这样,锁上的时间戳始终在2分钟内更新.您还需要创建另一个程序来删除旧的陈旧锁.这应该每隔几分钟就在一个cron作业中运行.它应该搜索时间戳大于5分钟左右的任何锁,然后删除.如果时间戳早于时间戳,那么显然编辑器会关闭一些如何或时间戳在2分钟内更新.

像其他人提到的那样,你应该尝试使用mysqli.它代表"MySQL Improved",是旧界面的替代品.


web*_*ave 1

为此(以及所有数据库操作)使用 PDO:

$value = 40;

try {
    $dbh = new PDO("mysql:host=localhost;dbname=dbname", 'username', 'password');
} catch (PDOException $e) {
    die('Could not connect to database.');
}

$dbh->beginTransaction();

try {
    $stm = $dbh->prepare("SELECT field FROM table WHERE ID = ? FOR UPDATE");
    $stm->execute(array($value));
    $dbh->commit();
} catch (PDOException $e) {
    $dbh->rollBack();
}
Run Code Online (Sandbox Code Playgroud)

如果你必须使用过时的 mysql_* 函数,你可以这样:

mysql_query('SET AUTOCOMMIT=0');
mysql_query('START TRANSACTION');
mysql_query($sql);
mysql_query('SET AUTOCOMMIT=1');
Run Code Online (Sandbox Code Playgroud)

  • 不要默默地投反对票。发表评论以帮助更好的答案。 (2认同)
  • 根据记录,我认为这个建议没有问题,它是前瞻性的! (2认同)