在 PHP 中锁定 MySQL INNODB 行
我有一个名为 meta
的表,其中有两列 name
和 value
。
在由许多客户端同时调用的 php 脚本中,我这样做:-
$mysqli->multi_query("SELECT id FROM links WHERE id > (SELECT value FROM meta WHERE name='scan') LIMIT 1000;UPDATE meta SET value=value+1000 WHERE name='scan';");
或者这样:-
$mysqli->multi_query("SELECT id FROM links WHERE id > (SELECT value FROM meta WHERE name='scan' FOR UPDATE) LIMIT 1000;UPDATE meta SET value=value+1000 WHERE name='scan';");
不幸的是,这并不似乎可以正常工作,因为客户端最终会得到重复的 id
。数据库负载很重,SELECT
需要几秒钟的时间。
I have a table called meta
, with two columns name
and value
.
In a php script, which is called by many clients concurrently, I do this:-
$mysqli->multi_query("SELECT id FROM links WHERE id > (SELECT value FROM meta WHERE name='scan') LIMIT 1000;UPDATE meta SET value=value+1000 WHERE name='scan';");
or this:-
$mysqli->multi_query("SELECT id FROM links WHERE id > (SELECT value FROM meta WHERE name='scan' <b>FOR UPDATE</b>) LIMIT 1000;UPDATE meta SET value=value+1000 WHERE name='scan';");
Unfortunately, this doesn't appear to work as clients are ending up with duplicate id
's. The database is heavily loaded and the SELECT
takes a few seconds.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一个复杂的问题;锁定和事务级别,但上面的神奇之处在于
BEGIN
语句。如果没有它,每个语句都会在自己的事务级别中运行,并且FOR UPDATE
锁会过早解锁。It's a complex issue; locking and transaction levels, but the magic above was the
BEGIN
statement. Without it, each statement was running in its own transaction level, and theFOR UPDATE
lock was being unlocked too early.首先尝试下面的实验,然后尝试根据您的要求进行映射。
创建表:
然后创建:
create rowlocking.php
上面的脚本将访问 id=5 的行并锁定其他事务直到 10 秒休眠时间。
创建 rowlocking1.php
上面的脚本尝试访问 id=5 的同一行。
现在,如果您运行脚本 rowlocking,并且在 10 秒睡眠时间内运行 rowlocking1,它将无法访问行 id=5,直到通过行锁定释放为止。一旦超过行锁定 10 秒的睡眠时间就能够访问行 id=5。
尝试将这个概念与您的脚本映射,您将获得 innoDB 行级锁定。如果您需要详细解释,请发表评论。
First try below experiment and then try to map as per your requirement.
Create table:
Then create:
create rowlocking.php
Above script will access a row with id=5 and locks for other transaction till 10 second sleeping time.
create rowlocking1.php
Above script tries to access same row with id=5.
Now if your run script rowlocking and within that 10 second sleeping time if you run rowlocking1 it will not able to access row id=5 till its release by rowlocking. Once 10 sec sleep time over rowlocking will be able to access row id=5.
Try to map this concept with your script you will get innoDB row level locking. Give a comment if you need detailed explanation.
这是您要找的吗?
我不确定这是否是您正在寻找的,但如果是这样,请记住在必要时/必要时解锁表,并确保您使用的帐户具有 LOCK 权限。
有关 INNODB 读锁的 MySQL 文档
Is this what you are looking for?
I'm not sure if this is what you are looking for or not, but if so remember to unlock tables afterward when/where necessary and make sure that the account you are using has LOCK privileges.
MySQL Documentation on INNODB READ LOCKS