2017-04-20 5 views
1

Wenn ich eine einfache Aussage als solche für eine InnoDB Tabelle habenInnoDB Select For Update

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

Gibt es eine Notwendigkeit, wirklich FOR UPDATE wähle?

Da InnoDB das Sperren auf Zeilenebene unterstützt, besteht die Möglichkeit einer Kollision, selbst wenn Tausende von Clients gleichzeitig dasselbe Skript ausführen?

Update:

So etwas würde verhindern, dass Schlösser

$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(); 

Antwort

1

Ja, können Kollisionen immer auftreten. So mit dem Design-Muster:

SELECT FOR UPDATE für alle Ressourcen in einer bestimmten Transaktion zuerst, kann Deadlock Situationen verhindern oder verkürzen.

Angenommen, das folgende Szenario:

  • Verfahren A Aktualisierungen Tabelle 1 & 2 in der Reihenfolge 1,2
  • Verfahren B Updates Tabelle 1 & 2 in der Größenordnung 2,1

Jetzt verarbeite Prozess A Aktualisierungen, Tabelle 1, wobei Prozess B Tabelle 2 zur gleichen Zeit aktualisiert, was zu einem Deadlock führt (Annahme ist, dass die gleichen "Datensätze/Seiten" von diesem Update betroffen sind).

Wenn jedoch die SELECT FOR UPDATE beim Start der Transaktion verwendet würde, würde die Transaktion beim Start fehlschlagen, da Tabelle 2 (oder 1, die schneller ist) nicht gesperrt werden kann. Der Schlüssel hier ist "Am Anfang der Transaktion", wenn Sie es später tun, dann nur das Ausführen der UPDATE ist genauso effizient.

Schlüssel ist immer, um Ihre Transaktionen atomar und schnell zu halten: Gruppieren Sie die SQL-Logik, so dass sie mit der geringsten Menge anderen Codes dazwischen ausgeführt werden kann, halten Sie die Sperrzeiten so kurz wie möglich.

+0

Ich aktualisierte die Frage mit Code, der funktionieren sollte. Vielen Dank! –

0

Wenn alles, was Sie tun müssen, um

ist
BEGIN; 
UPDATE ... 
COMMIT; 

dann tun nur so.

Wenn Sie dies tun müssen:

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

dann Sie Notwendigkeit FOR UPDATE tun eine andere Verbindung, um zu verhindern T. Ändern

Ohne FOR UPDATE wenn T geändert wurden, während Sie auf das Zeug gearbeitet, dann würdest du entweder die Änderungen, die sie machen, schrittweise machen. Oder sie könnten die Sachen ändern, die Ihre UPDATE inkorrekt machen.

Verwandte Themen