Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Dwie kopie skryptu naraz dobierają się do tego samego rekordu bazy danych
Forum PHP.pl > Forum > PHP
L_Devil
Witam!

Problem mam z moim serwisem bazującym na php 5 i mysql 4.1
Otóż mój skrypt musi co jakiś odcinek czasu (zwykle godzinę) zaktualizować pewne dane w bazie danych. Dotychczas robiłem to, sprawdzając przy każdych odwiedzinach, czy minęła już data aktualizacji, po czym zapisywał ową datę w bazie danych. Administrator serwera nie udostępnia mi Crona, tym niemniej to rozwiązanie działało... do niedawna. Niestety, niedawno mój serwis zyskał na popularności i zdarza się, że dwie kopie skryptu są uruchamiane niemal jednocześnie. Jak sprawić, by tylko jedna mogła zaktualizować bazę danych? Słyszałem coś o blokowaniu tabel, jak to zrobić i czy może pomóc w tym konkretnym przypadku?

Pozdrawiam
Mazur_pl
Możesz zrobić to tak:
Kiedy ktoś lub coś robi z bazą danych zapisuj jego session_id() w bazie .
Kiedy wejdzie druga osoba sprawdzasz czy jakiś wpis jest już w bazie danych. Jeżeli tak to blokujesz dostęp jeżeli nie to dopuszczasz . Potem przy wyjściu usuwasz wpis z bazy danych.

(To moja propozycja) .
dr_bonzo
TRANSAKCJE (kropka)
cicik
Cytat(Mazur_pl @ 29.05.2007, 22:08:53 ) *
Możesz zrobić to tak:
Kiedy ktoś lub coś robi z bazą danych zapisuj jego session_id() w bazie .
Kiedy wejdzie druga osoba sprawdzasz czy jakiś wpis jest już w bazie danych. Jeżeli tak to blokujesz dostęp jeżeli nie to dopuszczasz . Potem przy wyjściu usuwasz wpis z bazy danych.

(To moja propozycja) .


Wszelkie tego typu pomysły są ZŁE. We wszystkich tego typu pomysłach da się znaleźć taki scenariusz równoległego wykonania dwóch zapytań kiedy owy sposób nie zadziała.
Dlaczego? Dlatego, że w takich przypadkach operacje sprawdzenia czy jest nałożona blokada i nałożenia blokady są PRZERYWALNE co oznacza, że pomiędzy nie może sie wepchać inne żądanie.
Jedynym sposobem, tak jak kolega wyżej napisał, są TRANSAKCJE.
L_Devil
Dzięki, już googlam o Transakcjach mySql winksmiley.jpg
1010
Gdzieś kiedyś słyszałem że mysql ma wbudowaną taką blokadę w przeciwieństwie do sql.... Może się mylę
L_Devil
Oki, przegrzebałem dokumentację, ale mam problem jak to ładnie połączyć w całość:

robię tak:

  1. START TRANSACTION;
  2. SELECT value FROM config WHERE name='lasttime' LOCK IN SHARE MODE;
  3. -- Kod php sprawdza value i ocenia czy należy już dokonać aktualki. Jeżeli tak:
  4. -- Różne operacje
  5. UPDATE config SET value=value+3600 WHERE name='lasttime';
  6. COMMIT;
W tym problem, że zapytanie z Selectem wykona się bez względu na lock w każdej sesji - a więc może zajść sytuacja:
+jeden skrypt dostaje polecenie select i otrzymuje informacje, że już czas na aktualke
+druga kopia skryptu otrzymuje te same dane, nim pierwsza zdąży zaktualizować pole. Rozpoczyna swoją aktualizację, która jest wpisana w następną transakcje
+obie transakcje zostają wykonane jedna po drugiej - a więc błędnie

Jak sobie z tym poradzić? Co przeoczyłem? Zaznaczam, że korzystam z wersji mySQL 4.1 winksmiley.jpg
cicik
Jest taka składnia w sqlu SELECT ... FOR UPDATE.
Dla mysqla można poczytać o tym tutaj: http://dev.mysql.com/doc/refman/5.0/en/inn...king-reads.html

Edit:
Właśnie zauważyłem, że korzystasz z mysql 4.1. Nie wiem czy na tym da się zrobić cokolwiek.
L_Devil
MySQL 4.1

Wygląda na to, że jest... Czyli poprawne będzie zrobienie tego tak:
  1. START TRANSACTION;
  2. SELECT value FROM config WHERE name='lasttime' FOR UPDATE;
  3. -- Kod php sprawdza value i ocenia czy należy już dokonać aktualki. Jeżeli tak:
  4. -- Różne operacje
  5. UPDATE config SET value=value+3600 WHERE name='lasttime';
  6. COMMIT;

Gdyby druga kopia skryptu uruchomiła się w tej samej chwili, to z Selectem będzie musiała zaczekać? Tak? (Pytam bo nie wiem, a nie chcę popełnić błędu winksmiley.jpg )
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.