[英]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 UPDATE
或LOCK 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”解決方案而言,我在這里向您展示的內容背后的概念應該可以很好地為您服務。
我建議您為此使用session
...您可以將該id
保存到會話中...以便可以檢查一個客戶端是否正在檢查該記錄,而不是不允許另一個客戶端訪問它 ...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.