通过php实现mysql行锁定

通过php实现mysql行锁定,php,mysql,locking,row,Php,Mysql,Locking,Row,我正在帮助一位朋友使用一个基于web的表单,该表单适用于他们的业务。我试图让它准备好处理多个用户。我已经对其进行了设置,以便在显示记录进行编辑之前,使用以下代码锁定记录 $query = "START TRANSACTION;"; mysql_query($query); $query = "SELECT field FROM table WHERE ID = \"$value\" FOR UPDATE;"; mysql_query($query); (好吧,这大大简化了,但这就是mysql的

我正在帮助一位朋友使用一个基于web的表单,该表单适用于他们的业务。我试图让它准备好处理多个用户。我已经对其进行了设置,以便在显示记录进行编辑之前,使用以下代码锁定记录

$query = "START TRANSACTION;";
mysql_query($query);
$query = "SELECT field FROM table WHERE ID = \"$value\" FOR UPDATE;";
mysql_query($query);
(好吧,这大大简化了,但这就是mysql的本质)

它似乎不起作用。但是,当我从命令行直接转到mysql时,使用同一个用户登录并执行

START TRANSACTION;
SELECT field FROM table WHERE ID = "40" FOR UPDATE;
我可以有效地阻止web表单访问记录“40”,并获得超时警告

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

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

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

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

如果必须使用过时的mysql_*函数,您可以执行以下操作:

mysql_query('SET AUTOCOMMIT=0');
mysql_query('START TRANSACTION');
mysql_query($sql);
mysql_query('SET AUTOCOMMIT=1');

问题在于mysql命令。你可以用mysqli来做这个

或者PDO。此处描述:


HTH

您不应该使用mysql api,因为它很容易出错,从而启用sql注入之类的功能,并且缺少一些功能。我怀疑事务就是其中之一,因为如果我没有错的话,每个查询都是“自行”发送的,而不是在更大的上下文中发送的

不过,解决方案是使用其他一些api,我更喜欢mysqli,因为它与mysql非常相似,并且得到广泛支持。您也可以轻松地重写代码以使用mysqli

对于事务功能,请将自动提交设置为false,并在需要时提交自己。这与启动和停止事务相同

有关参考资料,请参阅:


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

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

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

不能在较长时间内锁定表格行进行编辑。这不是他们的设计。如果要锁定记录进行编辑,则需要在另一个表中跟踪这些锁定。创建一个名为“edit_locks”的新表,并存储要锁定的记录id、正在编辑的用户id以及锁定的时间。如果要打开一条记录进行编辑,请锁定整个“编辑锁定”表,然后查询该记录是否被其他人锁定。如果不是,请插入锁定记录,如果是,则显示锁定错误。当用户保存或取消时,从编辑锁定中删除锁定记录。如果你想让事情变得简单,只要在你的程序想使用它的时候锁定这个表就行了。这将有助于您避免比赛状态

还有一种情况可能会导致问题。如果用户打开一条记录进行编辑,然后在不保存或取消的情况下关闭浏览器,编辑锁将永远留在那里。这就是为什么我说商店上锁的时间。编辑器本身应该每隔2分钟左右进行一次AJAX调用,说“我仍然需要锁!”。当PHP程序收到这个“重新锁定”请求时,它应该搜索锁,然后将时间戳更新为当前值。这样,锁上的时间戳总是在2分钟内更新。您还需要创建另一个程序来删除旧的过时锁。这应该每隔几分钟在cron作业中运行一次。它应该搜索任何时间戳超过5分钟左右的锁,然后移除。如果时间戳早于此,那么显然编辑器已经关闭了,或者时间戳将在2分钟内更新


正如其他一些人提到的,您应该尝试使用。它代表“MySQL改进版”,是旧界面的替代品。

这是一个老话题,但人们可能仍在关注它。我使用了一种类似于JMack的方法,但是在我想要行锁定的表中包含了锁定信息。我的新专栏是LockTime和LockedBy。要尝试锁定,我执行以下操作:

UPDATE table
SET LockTime='$now',LockedBy='$Userid'
WHERE Key='$value' AND (LockTime IS NULL OR LockTime<'$past' OR LockedBy='$Userid')

cron作业可以删除旧锁,但这并不是必须的。

在第二次mysql_查询($query)之后,您做了什么?如果您的php脚本退出,则锁定释放这种方式有一些优点,但也有一些缺点。您需要不时清理锁定/解锁表。这是由崩溃或意外中断引起的。我个人不会用它。好的,杰马克,你已经扩展了你的答案,并在第二部分解释了缺点。可靠答案+1@Andreas我的描述中包含了一种清理锁表的方法,以便任何浏览器崩溃都会导致记录锁定时间不超过几分钟。@Andreas Oops,我们有点不同步。看起来我们的观点是一致的。非常感谢。你完全意识到了我的问题。因此,如果您需要自己实现整个锁定方案,“选择……更新”有什么用处吗?不要沉默地否决。请留下评论,以帮助更好地回答问题。作为记录,我认为这个建议没有问题,它是前瞻性的!我同意韦比·戴夫的观点。请让我知道你为什么这么做
UPDATE table
SET LockTime='$now',LockedBy='$Userid'
WHERE Key='$value' AND (LockTime IS NULL OR LockTime<'$past' OR LockedBy='$Userid')
UPDATE table
SET LockTime=NULL,LockedBy=''
WHERE Key='$value' AND LockedBy='$Userid'