簡體   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