【问题标题】:PHP/MySQL Synchronous innoDB queries works as asynchronousPHP/MySQL 同步 innoDB 查询作为异步工作
【发布时间】:2015-12-08 00:39:12
【问题描述】:

我需要使用不同的 PHP 脚本同时更新和读取一张表中的数据。 我创建 $sess 作为脚本会话标识符(同时工作大约 20 个脚本),并在表行中设置了 100 行的会话标识符。之后,它将通过会话标识符选择为此脚本保留的行。在 while 循环中,脚本将对数据进行一些处理并更新保留的行。

但是脚本不能同时工作,第一个脚本工作正常,但其他脚本在第一个脚本运行时不做第一个查询。我在我的数据库管理应用中看到它。

$sess = intval(str_replace(".", "", microtime(TRUE)));
sql_query("UPDATE locations SET sess='$sess' WHERE sess='0' LIMIT 100");
$r = sql_query("SELECT * FROM locations WHERE sess='$sess'");
while ($q = sql_row($r))
{

创建表语法

CREATE TABLE `locations` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `country_id` int(11) unsigned DEFAULT NULL,
  `area_id` int(11) unsigned DEFAULT NULL,
  `timeZone` int(2) DEFAULT NULL,
  `lat` double DEFAULT NULL,
  `lon` double DEFAULT NULL,
  `locationKey` int(11) unsigned DEFAULT NULL,
  `cityId` int(11) unsigned DEFAULT NULL,
  `sess` bigint(100) unsigned DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `lat` (`lat`),
  KEY `lon` (`lon`),
  KEY `country_id` (`country_id`),
  KEY `cityId` (`cityId`),
  KEY `area_id` (`area_id`),
  KEY `sess` (`sess`)
) ENGINE=InnoDB AUTO_INCREMENT=3369269 DEFAULT CHARSET=utf8;

【问题讨论】:

  • 您能澄清一下您的意思吗?包含您使用 sess 标志进行更新的原因可能会有所帮助,然后选择这些行并对其进行处理。
  • 嗨!我有location_id(我需要它通过http从服务器获取数据)在表位置和数据行中,我从服务器获取数据并将其放入此表中,一些数据放入其他表中。我在“while”循环中所做的一切。会话我需要为每个脚本保留 100 行。
  • 但我只是想知道这对 innoDB 来说是正常工作还是有什么问题?我曾经认为 innoDB 在行级别锁定表,如果与 MyIsam 表进行比较,我可以更新和插入其他行。我错过了什么?
  • 您在错误的地方寻找罪魁祸首。您能告诉我们如何运行这两个不同的脚本吗?您是否一次在浏览器中打开 2 个选项卡,然后一个脚本运行,而另一个脚本挂起?
  • 我通过启动的 http 获取请求来完成。是的,我在两个(或更多)不同的选项卡中使用浏览器进行操作。

标签: php mysql innodb


【解决方案1】:

您是否在事务中 (BEGIN...COMMIT)?如果是这样,您已经锁定了这 100 行。 autocommit=0 同上。

相反,请确保 UPDATE(用于将“队列”中的 100 个项目分配给您的进程)本身处于事务中。

然后,假设其他线程不能在同一微秒内调用microtime(一个可疑的假设),这 100 个项目将安全地分配给您。然后您可以启动另一个事务(如果需要)并处理它们。

但是,这 100 行 SELECT 将不必要地对这些行设置读锁。

所以...

START TRANSACTION;
UPDATE ... LIMIT 100;
SELECT ...
COMMIT;

foreach ...
    START TRANSACTION;
    work on one item
    COMMIT;
end-for

不清楚第二个 START-COMMIT 应该在 for 循环内还是在外。内部会慢一些,但可能是“正确的”,这取决于您正在做什么“工作”以及可能需要多长时间。 (你不想ROLLBACK 99 个成功的“作品”,因为第 100 个花了太长时间。)

你以后在做DELETE ... WHERE sess = $sess吗?如果您要像这样批量删除,请在 for 循环之后的单独事务中执行。

目标:将排队事务与应用事务分离。

请注意,隔离将使错误/死锁/等的编码变得更容易。 (你正在检查,对吗?)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 2020-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多