2017-04-20 80 views
1

如果我有一個簡單的語句,這樣的一個InnoDB表InnoDB的選擇對於更新

UPDATE <table> SET locked=1, col2=<Val2> WHERE locked=0 

是否有任何需要確實SELECT FOR UPDATE?

既然InnoDB支持行級鎖定,那麼即使有成千上萬的客戶端同時執行相同的腳本,是否還有碰撞的可能?

更新:

像這樣將防止鎖

$dbh = new PDO(DSN, DB_USER, DB_PASS); 
$dbh->beginTransaction(); 
$selQuery = $dbh->prepare("SELECT <col> FROM <table> WHERE status=0 LIMIT 1 FOR UPDATE"); 
$selQuery->bindColumn(<col1>, $col1); 
$selQuery->execute(); 

$selQuery->fetch(PDO::FETCH_BOUND); 

$dbh->query("UPDATE <table> SET status=1 WHERE status=0 LIMIT 1"); 

$dbh->commit(); 

回答

1

是的,總是會出現衝突。所以使用設計模式:

SELECT FOR UPDATE首先給定事務中的所有資源,可以防止或縮短死鎖情況。

假設以下情形:

  • 方法A的更新表1 & 2的順序1,2-
  • 方法B更新表1 & 2的順序2,1

現在處理A更新(表1),同時進程B更新表2,導致死鎖(假定此更新命中相同的「記錄/頁面」)。

但是,如果SELECT FOR UPDATE將在事務開始時使用,則事務在開始時將失敗,因爲表2(或1,更快的人)無法鎖定。這裏的關鍵部分是「在交易開始時」,如果您稍後再做,那麼只需運行UPDATE即可。

密鑰始終保持您的事務原子性和快速性:對SQL邏輯進行分組,以便它們可以用最少量的其他代碼執行,保持鎖定時間儘可能短。

+0

我用應該工作的代碼更新了問題。謝謝! –

0

如果你需要做的是

BEGIN; 
UPDATE ... 
COMMIT; 

然後做只。

如果你需要這樣做:

BEGIN; 
SELECT stuff from table T; -- needs FOR UPDATE 
work with the stuff, and eventually 
UPDATE T ...; 
COMMIT; 

那麼你需要FOR UPDATE防止改變T.

另一個連接,而不FOR UPDATE如果T,而你製作的東西發生了變化,那麼你要麼改變他們正在做的改變。或者他們可以改變使你的UPDATE不正確的東西。