2013-08-26 77 views
1

我有一個產生MySQL查詢會是這個樣子PHP腳本:PDO,多條語句,和比賽條件

INSERT INTO `dailydb`.`probact_actionstaken`(`dispatcher`) VALUES ('kryan'); 

SET @actionTakenId = LAST_INSERT_ID(); 

INSERT INTO `dailydb`.`probact_actionstaken_types`(`actionTaken`,`type`) 
VALUES 
    (@actionTakenId, 2); 

INSERT INTO `dailydb`.`probact_actionstaken_problems`(`actionTaken`,`problem`) 
VALUES 
    (@actionTakenId, 2); 

INSERT INTO `dailydb`.`probact_actionstaken_actions`(`actionTaken`,`action`) 
VALUES 
    (@actionTakenId, 3); 

INSERT INTO `dailydb`.`probact_actionstaken_text`(`actionTaken`,`input`,`value`) 
VALUES 
    (@actionTakenId, 3, '7576'), 
    (@actionTakenId, 4, 'B61'), 
    (@actionTakenId, 5, '4'), 
    (@actionTakenId, 6, 'kryan'), 
    (@actionTakenId, 7, 'test'), 
    (@actionTakenId, 8, 'testing new debug'); 

SELECT `index`, `timestamp` 
FROM `dailydb`.`probact_actionstaken` 
WHERE `index`[email protected]; 

(請注意,顯示此查詢的目的,所有值都手動搜索和替換上:someId與相應的值,因爲我’使用米準備的語句)

(還注意到,probact_actionstakenindex是一個自動遞增主鍵,probact_actionstakentimestamp默認爲的結果)

該查詢的目標是插入大量的相關數據(基於自動值probact_actionstakenindex存儲在@actionTakenId中),然後返回自動生成的indextimestamp以供使用(該腳本在使用此輸出的AJAX調用中調用)。

該查詢大部分執行正確:五個INSERT語句都將正確的值插入到數據庫中。我的問題是最後的SELECT聲明。我嘗試去通過與下面的PHP代碼查詢結果:

$statement = $dbh->prepare($query); 
$statement->execute($params); 

$output['results'] = array(); 
do 
{ 
    $output['results'][] = array(); 
    while ($result = $statement->fetch(PDO::FETCH_ASSOC)) 
    { 
     $output['results'][count($output['results'])-1][] = $result; 
     if (isset($result['index'])) 
     { 
      $output['index'] = intval($result['index']); 
     } 
     if (isset($result['timestamp'])) 
     { 
      $output['timestamp'] = $result['timestamp']; 
     } 
    } 
} while ($statement->nextRowset()); 

echo json_encode($output); 

的想法是使用do...while塊通過從INSERT語句的結果得到的,然後得到的那最後SELECT結果聲明,它存儲在我的$output中。

在我的本地機器上(運行PHP 5.4.4),這很好地工作。在具有PHP 5.3.10的服務器上,$statement->nextRowset()每次都返回false,所以我只得到第一個行集(因爲它的語句爲INSERT,它爲’)。請注意,實際插入無論正確工作,並且當我在phpMyAdmin ’的SQL功能中運行上述手動填充的查詢時,它將返回正確的結果(由插入的索引和時間戳組成的表)。

閱讀了解這些問題後,似乎這樣的多個語句是一個糟糕的主意,並且實際上,它們與真實的預處理語句一起工作,而我仍然使用默認的模擬預處理語句。所以我可以切換到$dbh->prepare$statement->execute的單獨電話,這將解決我的問題,但我’米擔心競爭條件。服務器使用Nginx,許多用戶可能同時輸入條目。我不想’ t要LAST_INSERT_ID()返回其他用戶’的條目,並將這些字段與錯誤的操作相關聯。

在MySQL或PHP內部是否有某些原因可以防止競態條件問題?我可以採取一些措施?還是有安全的方式來使用多個預處理語句?如果後者,它在PHP 3.5.10中工作嗎?

回答

1

我不希望LAST_INSERT_ID()返回其他用戶的條目,並將這些字段與錯誤的操作相關聯。

的LAST_INSERT_ID()函數返回在當前會話只,而不是另一個MySQL會話生成的最新的ID。

參見http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id

已生成被保持在基於每個連接的基礎上的服務器的ID。這意味着該函數返回給定客戶端的值是爲該客戶端影響AUTO_INCREMENT列的最新語句生成的第一個AUTO_INCREMENT值。即使它們生成自己的AUTO_INCREMENT值,該值也不會受到其他客戶端的影響。此行爲可確保每個客戶端都可以檢索自己的ID,而不必關心其他客戶端的活動,而無需鎖定或事務。

由於存在競爭條件的可能性,如果函數不受限於這種範圍,函數將毫無用處。

我不知道你在處理PHP 5.3和PHP 5.4之間的多結果查詢時看到的差異的答案。避免多重查詢被認爲是最佳做法。

在您的開發人員環境中使用相同版本的PHP(以及所有軟件),您將部署到生產環境中也被認爲是明智之舉。

+0

很高興聽到我在比賽場地上一無所知。我會將它切換到單個語句。我會在幾分鐘內讓你檢查你是否接受,因爲這看起來相當清晰,而且不太可能有另一個答案最好。 – KRyan