Pytanie Zrozumienie transakcji pys mysql


The Dokumentacja PHP mówi:

Jeśli nigdy wcześniej nie spotkałeś się z transakcjami, oferują one 4 główne   cechy: Atomowość, konsystencja, izolacja i wytrzymałość (ACID). W   warunki laika, każda praca wykonana w transakcji, nawet jeśli takowa jest   przeprowadzane etapami, gwarantuje się stosowanie do bazy danych   bezpiecznie i bez zakłóceń z innych połączeń, kiedy jest   zobowiązany.

PYTANIE: 

Czy to oznacza, że ​​mogę mieć dwa osobne skrypty php, które jednocześnie wykonują transakcje, bez wzajemnego ingerowania w nie?


ELABOROWANIE NA TEMAT, CO OZNACZAJĄ "WŚCIBSKI":

Wyobraź sobie, że mamy następujące employees stół:

 __________________________
|  id  |  name  |  salary  |
|------+--------+----------|
|  1   |  ana   |   10000  |
|------+--------+----------|

Jeśli mam dwa skrypty z podobnym / tym samym kodem i działają w tym samym czasie:

script1.php i script2.php (oba mają ten sam kod):

$conn->beginTransaction();

$stmt = $conn->prepare("SELECT * FROM employees WHERE name = ?");
$stmt->execute(['ana']);
$row = $stmt->fetch(PDO::FETCH_ASSOC);

$salary = $row['salary'];
$salary = $salary + 1000;//increasing salary

$stmt = $conn->prepare("UPDATE employees SET salary = {$salary} WHERE name = ?");
$stmt->execute(['ana']);

$conn->commit(); 

i zakładając, że sekwencja zdarzeń jest następująca:

  • script1.php wybiera dane

  • script2.php wybiera dane

  • script1.php aktualizuje dane

  • script2.php aktualizuje dane

  • script1.php Zdarza się commit ()

  • script2.php Zdarza się commit ()

Jakie byłyby w tym przypadku wynikające z tego wynagrodzenia?

  • Czy to byłoby 11000? Czy oznacza to, że 1 transakcja będzie nakładać się na drugą, ponieważ informacje zostały uzyskane, zanim nastąpiło zatwierdzenie?

  • Czy to byłoby 12000? Czy oznacza to, że niezależnie od kolejności, w jakiej dane zostały zaktualizowane i wybrane,? commit() funkcja zmusiła je do wystąpienia pojedynczo?

Zachęcamy do szczegółowego opracowania, w jaki sposób transakcje i oddzielne skrypty mogą zakłócać (lub nie ingerować) w siebie nawzajem.


18
2018-05-31 23:16


pochodzenie


Jestem prawie pewna SQLSTATE[23000]: Integrity constraint violation pojawi się błąd dla jednego z tych skryptów. Pytanie brzmi, który z nich, jeśli obaj biegną w tym samym czasie. - icecub


Odpowiedzi:


Nie znajdziesz odpowiedzi w dokumentacji php, ponieważ nie ma to nic wspólnego z php lub pdo.

Silnik stołowy Innodb w mysql oferuje 4 tzw poziomy izolacji zgodnie ze standardem sql. Poziomy izolacji w połączeniu z odczytami blokującymi / nie blokującymi będą determinować wynik powyższego przykładu. Musisz zrozumieć konsekwencje różnych poziomów izolacji i wybrać odpowiedni dla swoich potrzeb.

Podsumowując: jeśli użyjesz szeregowego poziomu izolacji z wyłączonym autocommitem, wynik będzie wynosił 12 000. Na wszystkich innych poziomach izolacji i szeregowalnych z włączonym autocommitem wynik będzie wynosił 11000. Jeśli zaczniesz używać blokowania, wynik może być 12 000 pod wszystkimi poziomami izolacji.


13
2018-05-31 23:39





Sądząc po danych warunkach (samotne oświadczenie DML), nie potrzebujesz tutaj transakcji, ale blokady stołu. To bardzo powszechne zamieszanie.

Potrzebujesz transakcji, jeśli chcesz się tego upewnić WSZYSTKIE twoje instrukcje DML zostały wykonane poprawnie lub w ogóle nie zostały wykonane.

Znaczy

  • nie potrzebujesz transakcji dla dowolnej liczby zapytań SELECT
  • nie potrzebujesz transakcji, jeśli zostanie wykonana tylko jedna instrukcja DML

Chociaż, jak to zostało odnotowane w doskonałej odpowiedzi od Shadow, ty może używaj tutaj transakcji z odpowiednim poziomem izolacji, byłoby to dość mylące. To czego potrzebujesz tutaj blokowanie stołu. Silnik InnoDB pozwala blokuj poszczególne wiersze zamiast blokować całą tabelę, a zatem powinna być preferowana.

Jeśli chcesz, aby wynagrodzenie wynosiło 1200, użyj blokad stołowych.

Lub - prostszy sposób - po prostu uruchom atomowy zaktualizuj zapytanie:

UPDATE employees SET salary = salary + 1000 WHERE name = ?

W takim przypadku wszystkie wynagrodzenia zostaną zapisane.

Jeśli Twój cel jest inny, lepiej wyraź go wyraźnie.

Ale znowu: musisz zrozumieć, że transakcje w ogóle nie ma nic wspólnego z wykonywaniem oddzielnych skryptów. Odnośnie twojego tematu warunki wyścigu nie interesują Cię transakcje, ale blokowanie tabeli / wiersza. Jest to bardzo powszechne zamieszanie i lepiej się tego nauczyć:

  • Transakcja ma to zapewnić zbiór z DML zapytania w ciągu jeden skrypt zostały pomyślnie wykonane.
  • blokowanie tabel / wierszy ma na celu zapewnienie, że inne wykonywanie skryptów nie będzie zakłócać.

Jedynym tematem, w którym transakcje i blokowanie interferuje jest impas, ale znowu - dzieje się tak tylko w przypadku, gdy transakcja korzysta z blokowania.


7
2018-06-01 03:47



Myślę, że pytanie miało na celu zrozumienie litery I z ACID, a nie wykonanie konkretnego działania w określony sposób. Przynajmniej tak to zinterpretowałem. Nie zgadzam się z tym, co napisałeś o blokowaniu tabeli. W innodb możesz wykonać blokowanie na poziomie wiersza za pomocą instrukcji select, więc nie musisz blokować całej tabeli, aby uzyskać 12000 na końcu. Zgadzam się, że w powyższym kodzie nie ma potrzeby wyboru, ponieważ cała operacja może zostać wykonana w pojedynczej aktualizacji. Ale jeśli jest to tylko przykład mający na celu zrozumienie izolacji transakcji, to służy temu celowi. - Shadow
Używam "blokowania tabel" jako terminu ogólnego, zauważając, że w przypadku innodb preferowane powinno być blokowanie na poziomie wiersza. Więc przyjmuję twój komentarz jako raczej problem z terminologią. Rozważając znaczenie pytania, jestem prawdopodobnie najlepszym facetem w kwestii zrozumienia pytań, odpowiadającym już od 15 lat. Pytanie ACID jako problem XY dla PO, dla którego właśnie natknęli się na badanie ich konkretnego problemu. Tak czy inaczej, myślę, że obie nasze odpowiedzi potwierdzają się nawzajem, czynią to lepiej dla czytelnika. - Your Common Sense


Niestety, "bez ingerencji" potrzebuje pomocy programisty. To potrzebuje BEGIN i COMMIT określić zakres "transakcji". I...

Twój przykład jest niewystarczający. Pierwsze zdanie wymaga SELECT ... FOR UPDATE. To mówi przetwarzaniu transakcji, że prawdopodobnie istnieje UPDATE nadchodzi dla rzędu (ów), który SELECT pobiera. To ostrzeżenie ma kluczowe znaczenie dla "zapobiegania zakłóceniom". Teraz na osi czasu czytamy:

  • script1.php BEGINs
  • script2.php BEGINs
  • script1.php wybiera dane (FOR UPDATE)
  • script2.php wybiera dane są zablokowane, więc czeka
  • script1.php aktualizuje dane
  • Zdarza się skrypt1.php commit ()
  • script2.php wybiera dane (i otrzyma nowo zatwierdzoną wartość)
  • script2.php aktualizuje dane
  • Zdarza się skrypt2. php commit ()

(Uwaga: to nie jest "zakleszczenie", tylko "czekanie".)


4
2018-06-03 06:14