背景
我有一个表,其中包含两个或多个 PHP 脚本将同时访问的数据。数据看起来像这样:
+--------+-------------------+-----------+-----------+
| ID | Start | End | Status |
+--------+-------------------+-----------+-----------+
| 1 | 1000 | 1500 | 0 |
| 2 | 1000 | 1500 | 0 |
| 3 | 1000 | 1500 | 0 |
| 4 | 1000 | 1500 | 0 |
+--------+-------------------+-----------+-----------+
PHP 脚本在启动时执行以下查询:
SELECT * FROM `table` WHERE `Status` = 0 LIMIT 1
然后 PHP 脚本执行从 start
值到 end
值(1000 到 1500)的循环。完成后,它将该行的 Status
更新为 '1'
。它会自动重定向到自身并重新启动整个过程。
我面临的挑战是:
如果我希望 2 个或更多相同的 PHP 脚本同时运行以访问相同的数据库,我如何确保它们不访问相同的记录?
更大的挑战是,如果我想在同一 PHP 脚本的多个实例上拆分从
start
到end
的循环,即每 100 values 是脚本的一个实例,在达到1100
后,将 MySQLStart
更新为1100
并重定向到从开始的同一脚本code>1101
到1200
等等,直到达到End
号码。在达到End
编号后,该记录的Status
将设置为1
并且它将移动到下一条记录。实际情况下,从头到尾大约一百万次,循环中执行了一些内存密集型函数,所以我需要将其分块。
关于行级锁定的所有知识,都是我在最近几分钟学到的;而且这些似乎都无法回答来自一个脚本的多实例锁定。
我应该考虑 session ID/cookie 吗?你有什么建议?
最佳答案
我建议:
使用支持行级锁定的
InnoDB
:ALTER TABLE `table` ENGINE=InnoDB;
使用
Status
的值来指示“进行中”;更明确一点,让我们使用 MySQL 的ENUM
类型:ALTER TABLE `table` ADD status_new ENUM('queued','in progress','complete') AFTER status; UPDATE `table` SET status_new = CASE status WHEN 0 THEN 'queued' WHEN 1 THEN 'complete' END; ALTER TABLE `table` DROP status;
在客户端中使用事务:
$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, FALSE); // pdo $mysqli->autocommit(FALSE); // mysqli (OOP) mysqli_autocommit($link, FALSE); // mysqli (procedural) mysql_query('START TRANSACTION'); // ext/mysql *
使用 locking read获取要处理的行:
SELECT * FROM `table` WHERE status_new = 'queued' LIMIT 1 FOR UPDATE;
将获取行的
状态
设置为'in progress'
:UPDATE `table` SET status_new = 'in progress' WHERE ID = ?
提交交易:
$dbh->commit(); // pdo $mysqli->commit(); // mysqli (OOP) mysqli_commit($link); // mysqli (procedural) mysql_query('COMMIT'); // ext/mysql *
处理完成后,再次
UPDATE
记录以将其标记为这样。
请注意,您正确检测并处理了每个阶段出现的任何错误。
* 请注意,自 2011 年 6 月以来,不推荐在新代码中使用 ext/mysql
,现在已在 PHP v5.5 中弃用。
关于php - 从两个或多个脚本访问/更新一个表的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16370893/