要回答你的第一個問題......
在使用事務時,你的查詢通常只要您連接而言執行。您可以選擇提交,保存這些更改或回滾,恢復所有更改。請看下面的僞代碼:
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服務器時,查詢會自動回滾。
謝謝你的回答!爲了確保我的理解正確,你的意思是說,如果我把所有的mysql查詢包含在一個事務中,並且你上面寫的場景發生了(兩個用戶同時訪問一個「獲勝」頁面),那麼它會只通過一個人?我需要檢查在交易開始時'number_remaining'是否等於1,但是正確嗎? – 2013-03-14 11:44:14
正確。對於我給出的示例,還需要確保將隔離級別設置爲可序列化,或者使用「select for update」來鎖定select上的行。取決於隔離級別,更新,刪除和插入語句也具有不同的鎖定行爲。 對每個查詢使用事務都可能導致死鎖,所以在對您的數據更新和準確至關重要時使用它們。 我已更新我的答案,以包含啓用交易的示例。 – 2013-03-14 21:22:51
非常感謝,這是一個很好的解釋!我不知道你提到的那些mysql選項。如果你不介意的話,我還有幾個問題:1.我在mysql文檔中查找了'serializable',它顯示它設置了「鎖定共享模式」。這實際上並不妨礙選擇行。我認爲應該使用'select ... for update',是否正確(阻止閱讀)? 2.在哪些情況下會使用交易產生僵局?爲什麼後續交易不會等到輪到他們呢? – 2013-03-14 23:32:14