2013-02-28 25 views
20

一個問題的兩個部分:獲取mysql的最後一個插入ID如何與事務一起工作? +交易問題

  1. 在我笨的腳本,我開始交易,然後插入一行,在INSERT_ID()設置爲PHP變量,將更多的行插入另一個表使用新的ID作爲外鍵,然後我承諾一切。

    所以我的問題是:如果在結束事務之前一切都沒有提交,如果甚至沒有插入任何內容,mysql如何返回最後一個插入ID?我的腳本完美地工作(幾乎),並在隨後的查詢中使用新ID。

    (我說「差不多」,因爲使用PDO mysql驅動程序,有時第一個插入應該返回insert_id()是重複的 - 它會插入兩次任何想法爲什麼會這樣? ?以獲取最後一個ID它永遠不會發生,如果使用的mysqli或MySQL驅動程序)

  2. 我第一次寫劇本沒有交易,所以我有一些代碼沿途爲MySQL錯誤檢查,如:

    if(!$this->db->insert($table, $data)) { 
        //log message here 
    } 
    

    一旦我將所有的mysql代碼包裝在事務中,這會如何影響mysql進程?它不會導致任何可見的錯誤(希望與上述問題無關),但是它應該被刪除嗎?

謝謝。

回答

27

要回答你的第一個問題......

在使用事務時,你的查詢通常只要您連接而言執行。您可以選擇提交,保存這些更改或回滾,恢復所有更改。請看下面的僞代碼:

insert into number(Random_number) values (rand()); 
select Random_number from number where Number_id=Last_insert_id(); 

// PHP

if($num < 1) 
    $this->db->query('rollback;'); // This number is too depressing. 
else 
    $this->db->query('commit;'); // This number is just right. 

已生成之前可以讀取的隨機數承諾,以確保它是適合保存它給大家看之前(例如提交和解鎖行)。

如果PDO驅動程序無法正常工作,請考慮使用mysqli驅動程序。如果這不是一個選項,你總是可以使用查詢'select last_insert_id()'作爲id;'而不是$ this-> db-> insert_id()函數。

要回答第二個問題,如果要插入或更新其他模型將要更新或讀取的數據,請務必使用事務。例如,如果「Number_remaining」列設置爲1,則可能會出現以下問題。

Person A reads 1 
Person B reads 1 
Person A wins $1000! 
Person A updates 1 to be 0 
Person B wins $1000! 
Person B updates 0 to be 0 

在相同的情況下使用事務會產生這樣的結果:

人A開始交易
某甲讀取 「1」 NUMBER_REMAINING
(該行已被鎖定,如果使用select for update
人B 嘗試閱讀Number_remaining - 被迫等待
人A勝 $ 1000
人A更新1爲0
人A承諾
某乙 讀取0
某乙不贏$ 1000個
某乙哭

你可能想在transaction isolation levels閱讀起來爲好。

小心死鎖的,它可以在這種情況下發生:

人A讀取行1(select ... for update
人B讀取行 2(select ... for update
人A試圖讀取行2, 被迫等待
人員B試圖讀取行1,被迫等待
人A到達innodb_lock_wait_timeout(默認50秒),並且是 斷開
人B讀取行1和正常繼續

最後,因爲某乙可能已經達到了PHP的max_execution_time,當前的查詢將完成獨立PHP的執行,但沒有進一步的查詢將被接受。如果這是一個autocommit = 0的事務,那麼當連接到你的PHP服務器時,查詢會自動回滾。

+1

謝謝你的回答!爲了確保我的理解正確,你的意思是說,如果我把所有的mysql查詢包含在一個事務中,並且你上面寫的場景發生了(兩個用戶同時訪問一個「獲勝」頁面),那麼它會只通過一個人?我需要檢查在交易開始時'number_remaining'是否等於1,但是正確嗎? – 2013-03-14 11:44:14

+1

正確。對於我給出的示例,還需要確保將隔離級別設置爲可序列化,或者使用「select for update」來鎖定select上的行。取決於隔離級別,更新,刪除和插入語句也具有不同的鎖定行爲。 對每個查詢使用事務都可能導致死鎖,所以在對您的數據更新和準確至關重要時使用它們。 我已更新我的答案,以包含啓用交易的示例。 – 2013-03-14 21:22:51

+2

非常感謝,這是一個很好的解釋!我不知道你提到的那些mysql選項。如果你不介意的話,我還有幾個問題:1.我在mysql文檔中查找了'serializable',它顯示它設置了「鎖定共享模式」。這實際上並不妨礙選擇行。我認爲應該使用'select ... for update',是否正確(阻止閱讀)? 2.在哪些情況下會使用交易產生僵局?爲什麼後續交易不會等到輪到他們呢? – 2013-03-14 23:32:14

相關問題