PHP - MySQL 行级锁示例

3

我看到了很多关于使用Select FOR UPDATE和锁定行的帖子,但是我没有找到任何解释当代码尝试读取被锁定的行时会发生什么的帖子。

例如,假设我使用以下代码:

$con->autocommit(FALSE);
$ps = $con->prepare( "SELECT 1 FROM event WHERE row_id = 100 FOR UPDATE");
$ps->execute();
...
//do something if lock successful
...
$mysqli->commit();

在这种情况下,我如何确定我的锁定操作是否成功?当行已经被锁定时,处理该场景的最佳方法是什么?
抱歉如果已经有相关描述,但我找到的都是顺利路径的解释。

4
通常情况下,SELECT查询不会锁定数据库,因为它们是只读操作且不涉及事务处理。 - Jay Blanchard
1
如果正在进行读取锁定,它将等待。并等待。(取决于您的SESSION TRANSACTION ISOLATION LEVEL)。但通常你会看到“陈旧”的数据(即:来自未提交交易的数据尚未到达,因此“陈旧”是有争议的),而不是在读取时遇到行锁定。 - Wrikken
所以,@Wrikken你的意思是我的代码应该假设锁定成功并继续逻辑处理,这样并发事务看起来就像之前已经完成的事务一样。基本上,如果Transaction 1锁定并进行更改,而Transaction 2尝试读取,那么对于Transaction 2来说,它将与Transaction 1非并发地发生但在T2的读取时间之前发生的方式相同。 - NEW2WEB
@JayBlanchard - 我在 SQL 中忘记了我的 FOR UPDATE。 - NEW2WEB
不,你没有。除非你提交事务,否则继续进行,而不会应用你的更改(只需尝试使用2个不同的mysql cli客户端,你就会看到)。然而,执行FOR UPDATE查询的事务将等待所有具有锁定的事务提交。另外:通常情况下,你不想阻止其他进程的读取,你想要这样做吗?如果是,请解释一下为什么。关于问题:“如何知道此锁定成功”:execute()返回true或false(或者:如果启用了异常,则在失败时抛出异常)。 - Wrikken
显示剩余7条评论
1个回答

5
在这种情况下,我如何确定我的锁定成功了?处理行已被锁定的最佳方式是什么?如果您尝试锁定的行已经被锁定,则mysql服务器将不会返回该行的任何响应。它会等待²,直到锁定事务被提交或回滚。显然,如果该行已经被删除,则您的SELECT将返回一个空结果集并且不会锁定任何内容。之后,它将返回由持有锁的事务提交的最新值。常规的Select语句将不关心锁并返回当前值,而忽略未提交的更改。因此,换句话说:只有在成功锁定时才会执行您的代码。 (否则等待²,直到先前的锁定被释放)
注意,使用FOR UPDATE也会阻止任何事务性SELECT在被锁定的时间内进行 - 如果您不想这样做,应该使用LOCK IN SHARE MODE。这将允许事务性选择使用当前值继续进行,同时只阻止任何更新或删除语句。
²查询将在定义的时间后返回错误innodb_lock_wait_timeouthttp://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout。然后它将返回ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 换句话说: 这是您尝试获取锁失败的时候。

附注:这种锁定仅适用于确保数据完整性。(即,在您插入引用此行的内容时,不会删除任何引用行)。

一旦锁定被释放,任何已阻止(或更好地称之为“延迟”)的删除语句都将被执行,可能会由于在刚插入的行上进行级联而删除您刚刚插入的行以确保完整性。

如果您想创建一个系统以避免2个用户同时修改相同的数据,则应在应用程序级别执行此操作,并查看悲观锁定和乐观锁定方法,因为长时间运行事务不是一个好主意。(我认为在PHP中,每个请求后数据库连接都会自动关闭,从而对正在运行的任何事务进行隐式提交)


非常好的回复。昨天我读了Wrikkn的回复,他提到在使用FOR UPDATE时仍然可以发生SELECTS,这让我感到困惑。我知道在某些情况下使用WHERE子句可以使您受益,但是您必须始终注意您正在使用的数据的所有不同类型的更新,以确保它们都包含在您的更新语句中。我不想这样做,因为有很多方法可以更新我正在查看的数据。我只想暂时“锁定”2或3个表中的几行,以便我可以更新它们,然后释放。 - NEW2WEB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接