繁体   English   中英

PHP脚本中需要的逻辑帮助

[英]Logical Help Needed in a PHP Script

我正在写一个小的PHP脚本,它只是使用下面的查询从MYSQL表返回数据

"SELECT * FROM data where status='0' limit 1";

读取数据后,我通过使用以下查询获取特定行的ID来更新状态

"Update data set status='1' WHERE id=" . $db_field['id'];

对于单个客户来说,一切都很好。 现在,我愿意为多个客户制作此特定页面。 超过20个客户端将几乎连续(24/7)在同一时间访问同一页面。 两个或多个客户端是否有可能从表中读取相同的数据? 如果是,那怎么解决呢?

谢谢

您可以考虑并发。 除非您只有1个PHP线程来响应客户端请求,否则实际上没有什么可以阻止它们各自从要处理的data分发相同的行-实际上,由于它们每个都将运行相同的查询,因此它们几乎肯定会在同一排。

解决该问题的最简单方法是锁定,如公认的答案所示。 如果PHP服务器线程运行SELECT...FOR UPDATELOCK TABLE ... UNLOCK TABLES (非事务性)所需的时间极短,这样其他线程可以等待每个线程运行此代码,则这可能会起作用SELECT...FOR UPDATE仍然很浪费,因为他们可能正在处理其他一些数据行,但稍后会再介绍)。

有一个更好的解决方案,尽管它需要更改架构。 假设您有一个这样的表:

CREATE TABLE `data` (
  `data_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `data` blob,
  `status` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`data_id`)
) ENGINE=InnoDB;

您没有任何方法来事务更新“下一个已处理的记录”,因为您唯一需要更新的字段是status 但是想象一下您的表看起来像这样:

CREATE TABLE `data` (
  `data_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `data` blob,
  `status` tinyint(1) DEFAULT '0',
  `processing_id` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`data_id`)
) ENGINE=InnoDB;

然后,您可以编写类似这样的查询来更新要使用“处理ID”处理的“下一个”列:

UPDATE data  
SET processing_id = @unique_processing_id 
WHERE processing_id IS NULL and status = 0 LIMIT 1;

任何值得一试的SQL引擎都将确保您没有2个不同的处理ID,这些ID表示要同时处理同一条记录。 然后,您可以在闲暇时

SELECT * FROM data WHERE processing_id = @unique_processing_id;

并且知道您每次都获得独特的记录。

这种方法也很好地解决了耐久性问题。 您基本上可以确定每个data行的批处理运行,这意味着您可以考虑每个批处理作业,而在此之前,您可能只考虑数据行。

我可能会通过为该元数据添加第二张表来实现@unique_processing_id(自动递增键是真正的窍门,但可以添加其他数据处理元数据):

CREATE TABLE `data_processing` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `data_id` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

并将其用作唯一ID的来源,您可能会得到如下结果:

INSERT INTO data_processing SET date=NOW();
SET @unique_processing_id = (SELECT LAST_INSERT_ID());
UPDATE data 
SET processing_id = @unique_processing_id 
  WHERE status = 0 LIMIT 1;
UPDATE data 
    JOIN data_processing ON data_processing.id = data.processing_id
  SET data_processing.data_id = data.data_id;
SELECT * from data WHERE processing_id = @unique_processing_id;
-- you are now ready to marshal the data to the client ... and ... 
UPDATE data SET status = 1 
    WHERE status = 0 
    AND processing_id = @unique_processing_id
LIMIT 1;

这样就解决了并发性问题,并根据设置data_processing表的方式使您处于更好的状态来审核持久性; 您可以跟踪线程ID,处理状态等,以帮助验证数据是否确实已在处理中。

还有其他解决方案-消息队列可能是理想的选择,允许您将每个未处理的数据对象的ID直接(或通过php脚本)排队到客户端,然后提供一个接口,供该数据的检索和标记处理与排队分开“下一个”数据。 但是就“仅mysql”解决方案而言,我在这里向您展示的内容背后的概念应该可以很好地为您服务。

您寻求的答案可能是使用交易。 我建议您阅读以下帖子及其接受的答案:

PHP + MySQL交易示例

如果没有,您还应该查看表锁定:

13.3.5锁定表和解锁表

我建议您为此使用session ...您可以将该id保存到会话中...以便可以检查一个客户端是否正在检查该记录,而不是不允许另一个客户端访问它 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM