2011-10-17 70 views
1

堆棧PHP應用程序:防止MySQL的死鎖在使用SELECT ... LOCK IN SHARE MODE

如果我沒有理解SELECT ... LOCK IN SHARE MODE正確的,你可以把它變成一個MySQL的交易選擇在該事務期間您將使用的行將從其他會話的寫入/刪除操作中「鎖定」這些選定行(但其他會話仍可以讀取行),直到事務完成,此時將鎖定行SELECT SHOCK IN SHARE MODE語句被釋放,所以其他會話可以訪問它們進行寫入/刪除等。

這正是我想要的我的評論表。無論何時將評論添加到我網站上的帖子中,我需要鎖定與該帖子關聯的所有評論行,同時更新所有鎖定行上的某些元數據。如果兩個評論同時提交,我不希望他們同時訪問相關的評論行,因爲他們基本上會互相影響(和元數據)。所以我想將SELECT LOCK IN SHARE MODE合併到註釋上傳腳本中,所以在查詢中運行鎖定的第一個會話將完全控制註釋行,直到它完成整個事務爲止(而稍微慢一點的腳本必須等到來自第一個腳本的整個事務執行)。

我是一個但擔心在腳本A鎖定腳本B需要的數據的情況下創建死鎖,而腳本B鎖定了腳本A需要的數據。我如何在應用程序中解決這個問題?

此外,我只在我的網站數據庫中使用innodb,所以我不需要擔心表鎖正確?

感謝,

Billmalarky

回答

0

在MySQL文檔中,14.6.8.1. InnoDB Lock Modes頁面討論(靠近頁面底部)所造成的第一個客戶端請求與「SHARE模式鎖定讀鎖定的死鎖情況「並且第二個客戶端因爲刪除而請求寫入鎖定。第二個客戶端被第一個客戶端的讀鎖鎖定,所以它的寫鎖被排隊。但是,當第一個客戶端然後嘗試做了刪除,將發生以下情況:因爲客戶端A需要一個X(獨佔)鎖刪除 行

發生死鎖在這裏。但是,該鎖定請求不能被授予,因爲客戶端B 已經有X鎖的請求,並且正在等待客戶端A到 釋放其S(共享)鎖定。由於B先前請求X鎖,因此A所持有的S鎖也不能升級到X 鎖。因此,InnoDB爲客戶端A生成一個錯誤並釋放它的鎖。在 點上,可以授予客戶端B的鎖定請求,並且B從表中刪除 行。

如果我理解正確此,我認爲這個問題可以通過使用FOR UPDATE而不是「鎖定共享模式」的第一個客戶端來解決。這會導致第一個客戶端從頭開始寫入鎖定,然後永遠不必等待第二個客戶端。

在查詢和更新語句周圍使用事務,鎖將一直保留,直到您提交事務。沒有其他表鎖應該是必要的。