PHP - MySQL行级锁定示例

时间:2014-10-29 16:50:47

标签: php mysql mysqli innodb rowlocking

我看过很多帖子,解释了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();

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

很抱歉,如果在某处描述了这一点,但我似乎找到的只是“快乐路径”的解释。

1 个答案:

答案 0 :(得分:5)

  

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

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

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

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

常规Select语句不会关心锁定并返回当前值,而忽略了存在未经修改的更改。

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

请注意,使用FOR 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):超过锁定等待超时;尝试重新启动交易

换句话说:这就是你尝试获取锁定失败的原因。


Sidenode:这种锁定只是适合于确保数据完整性。 (即,在插入引用该行的内容时,没有删除引用的行)。

一旦锁定被释放,任何被阻止(或更好地称之为延迟)的删除语句将被执行,可能会删除您刚刚插入的行,因为Cascading在您所在的行上只是握住锁以确保完整性。

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