2009-09-25 26 views
2

我想插入一些值到一個表中,它有一個自動遞增字段作爲主鍵。然後,我想通過使用mysql_insert_id()來檢索該ID,並將此ID用作另一個表中的外鍵。問題是 - 雖然不太可能 - 可能發生在第一次插入和稍後檢索之間,另一次插入發生在第一個表中,因此將返回錯誤的ID。我應該如何處理PHP中的查詢同步?

PHP會自動處理,還是我的顧慮是有效的?如果是這樣,我該如何克服它們?

回答

4

mysql_insert_id()將返回每個連接基上的最後一個插入的ID。所以基本上,你不必擔心併發腳本請求,如果這是你的擔心。

僅供參考:see the MySQL docs

編輯:

順便說一句,你可以很容易地進行測試。

test.php的

<?php 

    $sleep = isset($_GET[ 'sleep' ]) ? true : false; 

    $conn = mysql_connect(/* your parameters */); 
    mysql_select_db(/* your db */, $conn); 

    $sql = 'INSERT INTO yourtable(id,col1,col2) VALUES(null,"test","test")'; 
    mysql_query($sql); 

    if($sleep) sleep(5); 

    echo mysql_insert_id(); 
?> 

打開兩個瀏覽器選項卡:

請求這在第一:
http://localhost/test.php?sleep=1

請求這在第二內,比方說,4秒最大:
http://localhost/test.php

F第一次請求應該給你一個小於第二次請求的ID。

+0

+1 - 我很確定php函數只是爲last_insert_id()做了一個查詢,它說:「生成的ID在每個連接的基礎上保存在服務器中,這意味着函數返回的值到給定的客戶端是由該客戶端影響AUTO_INCREMENT列的最近語句生成的第一個AUTO_INCREMENT值「 – ryeguy 2009-09-25 17:57:35

+0

@ryeguy:我也這麼認爲。我甚至相信PHP的mysql_insert_id()是C API的mysql_insert_id()的代理。 (不完全確定,但我認爲我已經看到過關於其他PHP函數的提及,所以它不會讓我感到驚訝)。 C API函數在我提到的MySQL文檔中被提及。 – 2009-09-25 18:09:48

3

SQL transactions是你需要的。在MySQL中,InnoDB是唯一支持事務的引擎。

+0

不知道爲什麼這downmodded(當然,這是一個PHP的問題...),但基本上 - 如果你有一個查詢依賴於另一個查詢的結果,你需要使用交易。其他任何東西都是黑客。 (然而,最後一個插入ID是MySQL的特例。) – jrockway 2009-09-25 18:23:42

+0

不使用事務可能不是ACID,但這並不意味着它是黑客。有很多數據關係可以安全地操作而不需要交易。知道哪些做什麼,哪些不做是一個不同的問題。但不要以爲所有的數據庫應用程序都必須有事務。 – jmucchiello 2009-09-25 18:40:32

-2

您可以使用兩種常規策略來確保此問題不會影響到您。首先,您可以使用交易(如另一位作者所指出的)。

但是從性能角度來看,手動跟蹤Id號碼可能會更快。您可以通過在數據庫中使用全局標識來完成此操作。滾動號碼使系統中的id在全球獨一無二。

可以說全局ID是100,你知道你將需要6個ID。然後你寫出106到全局id表中的全局id行......然後你使用101作爲第一個入口,這是102數據點中的外鍵,依此類推。在處理大型數據集時,這大大提高了性能。

因此,如果您需要製作100個新的插頁,這可能是一個好主意。如果您一次只需要6個..使用交易...

正如jmucchiello在評論中所建議的那樣。您可以使用Update語句來確保另一個進程不寫入全局id條目。喜歡的東西

更新globaltable集ID = 106其中id = 100

我可以看到,我收到改裝下來這個答案,但是這真的是最好的策略,如果你有一百萬行導入.. 。 好吧...

-FT

+0

但是,如果兩個併發查詢從數據庫中檢索到相同的全局ID(這可能發生,因爲讀取,決定和重寫不是原子操作),它們將開始使用相同的ID,這在您需要唯一鍵時不會被允許。 – kahoon 2009-09-25 18:18:31

+1

kahoon:update globaltable set id = 106其中id = 100。假設這是整個事務(或者您正在使用不支持事務的mysql數據庫),那麼您將擁有原子性。 – jmucchiello 2009-09-25 18:36:11

+0

kahoon:正如jmuchhiello指出的那樣,如果其他進程正在更新全局ID,那麼ID將不會是100 ...並且什麼都不會改變。當然,您需要檢查查詢結果。令我感到意外的是,我被拒絕了,因爲如果不方便,我的方法是可行的,我不會假裝它是不方便的。好吧。 – ftrotter 2010-12-21 08:50:24