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

1 回答 1

5

在这种情况下,如何确定我的锁定是否成功?当行已被锁定时,处理场景的最佳方法是什么?

如果您尝试锁定行已被锁定 - mysql 服务器将不会为此行返回任何响应。它将等待²,直到锁定事务被提交或回滚。

(显然:如果该行已被删除,您SELECT将返回一个空结果集并且不锁定任何内容)

之后,它将返回由持有锁的事务提交的最新值。

常规Select语句将不关心锁并返回当前值,忽略存在未提交的更改。

因此,换句话说:您的代码只会在锁定成功时执行。(否则等待²直到先前的锁被释放)

请注意, usingFOR UPDATE还将在锁定时间阻止任何事务性 SELECTS - 如果您不想要这个,您应该使用它LOCK IN SHARE MODE。这将允许事务选择继续当前值,同时阻止任何更新或删除语句。

² 查询会返回错误,在innodb_lock_wait_timeout http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout定义的时间 之后会返回ERROR 1205 (HY000): Lock wait超时;尝试重启事务

换句话说:这就是您尝试获取锁失败的地方。


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

一旦锁被释放,任何阻塞(或者更好地称之为延迟)的删除语句都将被执行,可能会删除你刚刚插入Cascading的行,因为你刚刚持有锁以确保完整性。

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

于 2014-10-29T18:13:32.027 回答