2013-07-24 124 views
1

我在2個訪問MySQL數據庫的應用程序中使用UniDAC(Devart)。 在某個應用程序進行的某些繁重的更新更新操作中,偶爾會出現錯誤「嘗試獲取鎖定時發現的#40001死鎖;嘗試重新啓動事務」。在閱讀MySQL提示以應對這種情況後,他們說要重試交易。我的問題是要知道在Delphi中做到這一點的最佳方式。我這樣做:避免死鎖MySQL/UniDAC/Delphi

transaction_completed_ok:= False; 
repeat 
    try 
    my_db.StartTransaction; 
    (... do the inserts) 
    my_db.Commit; 
    transaction_completed_ok:= True; 
    except 
    my_db.Rollback; 
    Sleep(1000); 
    end; 
until transaction_completed_ok; 

這樣做每一筆交易,在兩個應用程序,是處理問題的一個有效方法是什麼?任何人都可以分享最佳方式嗎?歡迎任何幫助。

+1

不需要'Sleep()',因爲鎖已經被競爭事務獲得,因此立即重試這個鎖將導致它等待獲取鎖而不是死鎖。此外,您可能想檢查事務失敗的原因,因爲您可能希望以不同的方式處理死鎖以外的其他情況。 – eggyal

回答

2

您的錯誤重新啓動事務代碼無法解決問題,因爲重新執行一個相同的代碼會導致相同的錯誤。例如,如果您的代碼導致違反唯一性,那麼應用程序將會卡住。爲了解決這個問題,你應該重新組織應用邏輯,以避免死鎖。

connection1 locks tableA; 
connection2 locks tableB; 
connection1 attempts to lock tableB - waits for connection2 to unlock tableB; 
connection2 attempts to lock tableA - waits for connection1 to unlock tableA. 

作爲結果,我們得到了一個死鎖:當兩個並聯連接試圖鎖定以不同的順序2個表,例如發生 死鎖。爲了避免死鎖,您應該設置相同的表鎖定爲了讓這兩個連接,例如:

connection1 locks tableA; 
connection2 locks tableA; 
connection1 locks tableB; 
connection2 locks tableB. 

您可以在http://dev.mysql.com/doc/refman/5.1/en/innodb-deadlocks.html

閱讀有關死鎖的更多信息,爲了解決這個問題,你可以使用下面的算法:

+0

如果您在2個不同的應用程序中使用2個不同的連接,這不會解決,除非您讓它們之間進行通信。 –