2009-10-12 127 views
1

在PHP中處理MySQL死鎖的最佳做法是什麼?我是否應該將所有數據庫調用都封裝在try {} catch {}塊中,並從數據庫中查找DeadLock錯誤代碼?然後我是否再次重新發布整個交易(我認爲失敗的回滾)?通過PHP檢測MySQL死鎖

回答

5

死鎖返回錯誤1213你應該在客戶端處理

注意死鎖和鎖等待是不同的東西。在僵局中,沒有「失敗」的交易:他們都有罪。無法保證哪一個會回滾。

死鎖發生在這樣的場景:

UPDATE t_first -- transacion 1 locks t_first 
SET  id = 1; 

UPDATE t_second -- transaction 2 locks t_second 
SET  id = 2; 

UPDATE t_second -- transaction 1 waits for transaction 2 to release the lock on t_second 
SET  id = 2; 

UPDATE t_first -- transaction 2 waits for transaction 1 to release the lock on t_first. DEADLOCK 
SET  id = 2; 

你確定你不鎖等待混淆呢?

只要事務嘗試鎖定已被另一個事務鎖定的資源,就會發生鎖定等待。

在上面的示例中,在步驟3上發生鎖定等待。

由於這是一種正常情況(不像死鎖),可以通過提交或回滾持有鎖的事務從外部解決,因此InnoDB不會嘗試回滾持有該鎖的事務。

取而代之,它將取消在超時發生後嘗試獲取鎖的語句。

默認的超時時間爲50秒,使用innodb_lock_wait_timeout進行設置。

失敗的語句(試圖通過獲取的鎖)將返回錯誤1205

+0

@RomanNewaza:因爲交易雙方鎖定兩個表,儘管在不同的順序。 – Quassnoi 2013-01-29 07:27:52

+0

是的,我明白了。謝謝! – 2013-01-29 07:53:09

3

我想從這些引用溫暖的話語MySQL的How to Cope with Deadlocks

常作準備,如果它因爲死鎖而失敗重新發出一個事務。僵局並不危險。再試一次。

這可以通過這樣的方式來實現:

for ($i = 3; true; $i--) { 
    $pdo->beginTransaction(); 
    try { 

     // Do the unit of work 

     $pdo->commit(); 
     break; 

    } catch (\PDOException $e) { 
     $pdo->rollback(); 
     if ($i <= 0) { 
      throw $e; 
     } 
    } 
}