2
我有一些(PHP)代碼在InnoDB表上執行關鍵更新。我可以繞過MySQL中的當前事務嗎?
我正在使用(SELECT ... FOR UPDATE),所以我需要在事務中。
當從表單發佈數據時,此代碼正在執行,並且我有一個消息系統,以便將錯誤/成功消息存儲在數據庫中,並在下次頁面呈現時從數據庫中提取。
一些僞代碼: (我ommitting的東西,如try/catch塊和逃避,我在我真正的代碼)
beginTransaction();
query("SELECT * FROM `table` WHERE id=1 FOR UPDATE");
$x=$_POST[$x];
query("UPDATE `table` SET `field` = $X");
//add other data in the db related to $X
query("INSERT INTO `othertable` (x,y,x) VALUES (......)");
//check for various errors...
$erros=0
if ($error_condition_1) {
messageSystem("Error Condition 1!")
$errors+=1;
}
if ($error_condition_2) {
messageSystem("Error Condition 2!")
$errors+=1;
}
if ($errors) {
rollBackTransaction();
} else {
commitTransaction();
}
的問題應該是顯而易見的:當messageSystem存儲錯誤的數據庫的更改將稍後回滾,並且用戶將永遠不會看到錯誤消息。
有兩個簡單的解決方案,我可以看到:
- 修改我的代碼,以便
messageSystem
被稱爲事務之外。但是,如果我可以像上面那樣內聯,它的可讀性和編寫速度更快。另外,如果這是可能已經在嵌套事務中的庫代碼呢? - 修改
messageSystem
,以便它使用自己的連接到數據庫。但是,如果我使messageSystem更復雜,並決定在將消息添加到該會話之前需要鎖定session
表中的條目,該怎麼辦?這可能會導致死鎖,如果我的主代碼也出於某種原因鎖定了會話。 - 在交易前檢查錯誤。但實際上我需要鎖定相關的行,方法是在之前選擇'FOR UPDATE'我可以驗證輸入。
所以我的問題:有沒有辦法在一個(可能是嵌套的)事務中提交X,以至於如果事務回滾了,X仍然會被提交。
另外,是否有避免我所描述的問題的任何好方法。
謝謝!
是的,這是我目前的解決方案,也許是最好的選擇(+1),但我真的想知道是否有其他方法。 – DaedalusFall
你應該假定每個連接都是爲了自己的特定目的,這樣事務隔離才能正常工作。如果你需要使用數據庫的原因不同(在這種情況下記錄),使用其他連接是正確的方式。 – mikebabcock
明智的分離,我認爲你適合這種情況。但是當它變得更復雜時呢?我已經有一個外鍵約束從我的消息表到我的會話表(所以剩下的消息會在會話消失時被刪除)。在上面的代碼中會話可以被刪除。我可以處理這個問題,但是分離已經不是100%乾淨了。我對備選答案感興趣,所以我可以在更復雜的情況下處理它,但情況可能不會那麼好。對不起,這麼長的評論。 – DaedalusFall