Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: php <-> db - baza danych jest blokowana na czas nawiązania połączenia - mit?
Forum PHP.pl > Forum > Bazy danych
xamil
Chciałbym rozwiać moje wątpliwości co do pewnego tematu. Mianowicie chciałbym się dowiedzieć jak to jest ze skryptami php nawiązującymi połączenie z bazą danych i wykonującą szereg zapytań. Dajmy na to mamy taki o to kod:

  1. <?php
  2. $result=mysql_query("SELECT COUNT(*) clients_count FROM clients;", $connection);
  3. $row=mysql_fetch_assoc($result);
  4. echo $row['clients_count'];
  5. mysql_query("SELECT COUNT(*) clients_count FROM clients;", $connection);
  6. echo $row['clients_count'];
  7. ?>


Czy jest szansa aby pierwszy zwrócony wynik różnił się od drugiego? Innymi słowy czy pomiędzy wykonywane zapytania do bazy danych przez skrypt php mogą wbić się inne zapytania wykonywane np. przez inny skypt? Czy może się zdażyć tak, że podlicze sobie rekordy i wyjdzie mi powiedzmy 30 a gdy spróbuje wykonać na nich jakąś operacje to może mi sypnąć błędem bo np. inny skrypt je w tym czasie usunął?

Do tej pory myślałem, że tak to nie działa. Ktoś mi tam kiedyś mówił, że jest to nie możliwe bo baza jest blokowana na czas połączenia ale dziś przy okazji dokształcania się czytam sobie o pdo i natrafiłem na funkcję "PDO->beginTransaction()", "PDO->commit()" i
"PDO->rollBack()" które o ile dobrze zrozumiałem mają właśnie służyć blokowaniu takiej możliwości (no i jeszcze dodaje możliwoś cofnięcia zmian). Może jednak się mylę.

Bardzo proszę o odpowiedź i rozwianie moich wątpliwości jak to faktycznie działa.
Zbłąkany
To nie jest mit :-) Tranzakcje służą do wykonywania ciągu zapytań, które muszą być wykonane jedna po drugiej, bez ingerencji w dane z zewnątrz (i ewentualniew razie jakiegoś błędu, czy nieścisłości można wszystkie wprowadzone wcześniej zmiany cofnąć za pomocą metody rollBack()). Oczywiście dana baza ma swój własny wewnętrzny sposób blokowania rekordów. Do czego zmierzam: otóż tranzakcje to element języka SQL. Rozpoczęcie tranzakcji powoduje automatyczne zablokowanie bazy dla innych zapytań, na czas zakończenia obecnej tranzakcji. Ale nie raz okazuje się, że nie potrzeba blokować całej bazy, na której pracujemy tylko jedną, bądź kilka tabel i wtedy można blokować tabelę, bądź grupę tabel smile.gif . Co do konkretnych systemów bazodanowych: Microsoft SQL Server 2000 (zerknij też do BOL z Microsoftu), PostgreSQL - tranzakcje i blokady tabel, MySQL biggrin.gif . Co do innych baz, nie wiem/testowałem/sprawdzałem smile.gif
kwiateusz
ale podczas pojedynczych komend typu select baza raczej nie jest blokowana... nawet jak ich jest kilka pod rzad z jednego skryptu smile.gif bo np jesli skrypt zacząłby sie w kolko wykonywac i czekałby do timeoutu np. 30 sek to baza miałaby tyle być zablokowana? tak moim zdaniem
xamil
Cytat(Zbłąkany @ 22.02.2007, 22:52:48 ) *
To nie jest mit :-)
Przez obalanie mitu chodziło mi o obalanie tezy, że baza jest blokowana od połączenia do jego zakończenia. Albo inaczej, że mam pewność, że między zapytaniami nie wbije mi się jakieś zapytanie z zewnątrz wpływające na działanie mojej aplikacji.

Hmmm... nie do końca zrozumiałem odpowiedzi więc może jeszcze innaczej:
1. Mamy możliwość blokowania w php bazy danych - fajnie. Czy było to też w php4? Czy moze tylko tak jak wspomniałeś przez zapytanie SQL?
2. Czy jest możliwe ustawienie w bazie danych czegoś w stylu, że w momencie połączenia (z php) jest baza blokowana aż do zakończenia połączenia? W sensie czy można zablokować taką możliwość błędu jak opisałem na wstępie na poziomie bazy tak aby aplikacja php nie musiała się przejmować? Jeśli tak to czy się to faktycznie stosuje (przypuszczam, że nie ze względu na wydajność)?
3. Transakcje a wydajność? Czy bardzo spowolni działanie bazy danych ustawienie transakcji dla jakiegoś szeregu zapytań? Czy np. jest sens ustawienia transakcji na początku skryptu php i usunięcia dopiero na końcu?
4. Ostatnie najważniejsze pytanie. Poprzednie były abym lepiej temat zrozumiał;) Czy się powinienem przejmować tym co opisałem? Czy może szansa, że zapytanie się wbije w jakiś szereg zapytań jest zbyt znikoma aby się tym przejmować? Może jest coś innego co tak naprawdę czuwa nad tym tym wszystkim tak, że się nie muszę tym przejmować? Prawda jest taka, że jak otrzymujemy żądanie to wszystkie zapytania od początku działania skryptu aż po jego kres powinny mieć te same dane do obróbki.

p.s. Głównie chodzi mi o mysql
Zbłąkany
@xamil:

Ad. 1 Coś takiego było również w PHP4, ponieważ tranzakcje to nie jest element składni PHP tylko jest to element języka SQL:
  1. <?php
  2.  
  3. // To jest przykład dla PHP < 5
  4. $t = mysql_query('BEGIN TRANSACTION;',$resource);
  5. $s = mysql_query('SELECT * FROM some_table;',$resource);
  6. $i = mysql_query('INSERT INTO some_table (some_col1,some_col2) VALUES ('.$some_val1.','.$some_val2.');',$resource);
  7. if ( ! $i ) {
  8. // Kiedy coś nie poszło tak jak miało pójść cofamy tranzakcję, czyli przywracamy s
    tan bazy sprzed rozpoczęcia tranzakcji
  9. $t = mysql_query('ROLLBACK;',$resource);
  10. } else {
  11. // Jeśli wszystko jest ok zatwierdzamy zmiany
  12. $t = mysql_query('COMMIT;',$resource);
  13. }
  14.  
  15. // W PHP 5 przy użyciu PDO, nie trzeba wykonywać zapytań odnośnie tranzakcji bo sł
    użą do tego metody:
  16. // beginTransaction(), commit(), a także rollBack()
  17. ?>


Ad. 2 Patrz kod powyżej, jak można to zrobić z poziomu PHP i wtedy aplikacja nie musi się tym przejmować. Odnośnie zrobienia tego na samej bazie: nie da się tego tak prosto zrobić smile.gif , a nawet jeśli udałoby się coś takiego ustawić, to skutki tego byłyby opłakane (wysoki czas wykonania zapytań, itd...)

Ad. 3 Wszystko zależy od jakości twego kodu. Jeśli będzie on napisany z głową to na wydajności nie stracisz smile.gif . Inaczej ma się sprawa z logicznym podejściem bo tranzakcje stosuje się raczej do kilku powiązanych ze sobą insert'ów lub update'ów (oczywiście czasem zachodzi potrzeba na komendzie select, ale to na prawdę rzadko) .

Ad. 4 Oczywiście, że powinieneś się tym przejmować, bo aby twoja aplikacja działała dobrze przy dużej ilości odwiedzin, czyli przy kilkudziesięciu wykonaniach skryptu na sekundę. Szansa, że coś się wbije pomiędzy te zapytania jest wprostproporcjonalna do ilości odwiedzin strony/serwisu www. Im więcej odwiedzin tym większe prawdopodobieństwo, że jednak ktoś trafi w przerwe i będzie źle tongue.gif Niestety nie ma żadnej alternatywy, jeśli idzie o ten problem (blokowania dostępu do danych). Niekoniecznie skrypt musi działać na tych samych danych smile.gif Jeśli, np.: wyświetlasz, a nie obrabiasz (dane) to nic nie szkodzi, jeśli gdzieś po drodze zostanie dodana grupa rekordów (według odpowiedniego schematu wprowadzania danych).

Mam nadzieję, że zrozumiałeś temat smile.gif

@kwiateusz:

Wiele baz ma swoje wewnętrzne systemy blokowania i izolacji zapytań na bazie (np. Microsoft SQL Server, Oracle, itd...). My możemy wymusić dodatkową izolację, bądź też blokadę. Z tym, że domyślne mechanizmy blokowania i izolacji operują na samych tabelach, tak by jakieś inne zapytanie nie rozwalilo struktury tabeli. Taka blokada jest ściągana po wykonaniu zapytania.
xamil
Ad.1. Nie potrzebnie aż tyle sie upisałeś;) W pytaniu mi chodziło jedynie czy w php4 były funkcje do tego czy trzeba było sobie radzić przez zapytania sql. Dzięki.

Ad.2-4. Dzięki za wyjaśnienia. Czyli nie pozostaje nic innego jak mieć na uwadze od dziś transakcje. Jak to tak wszystko przeanalizowałem to z jednej strony źle nie jest z moimi poprzednimi kodami z drugiej jest;)
Jeśli w kodzie występowały jakieś powiązane zapytania select to raczej nic złego stać się nie mogło. Po pierwsze dlatego, że zazwyczaj potrzebną serię danych pobierałem jednym zapytaniem stosując LEFT JOIN. Dlatego jedyne przypadki gdzie trzeba było wykonać dwa selecty to najpierw COUNT(*) na rekordach a potem pobranie ich. To również nie mogło skutkować jakimiś poważnymi konsekwencjami bo co najwyżej liczba wyników wyświetlona na stronie mogła się później nie zgodzić z faktyczną ilością (aby zabezpieczyć się przed tak trywialnym błędem nie widzę nawet sensu stosowanai transakcji). Problem jaki mogłoby sprawić to INSERT do kilku tabel które to dane stanowią jedną logiczną całość. Np. w jednej userzy a w drugiej uprawnienia ich. Wtedy po dodaniu usera a przed dodaniem uprawnień może wbić się jakiś SELECT pobierający użytkowników a wtedy mamy klops bo wyświetlą się nie pełne dane.

Najgorsze w tym wszystkim jest to, że nigdy nie zdażyła mi się sytuacja właśnie wczytania takich częściowych danych choć jest to możliwe:/ Dlatego czy ktoś może to jeszcze potwierdzić co zostało tu napisane?winksmiley.jpg

@Zbłąkany: Dzięki wielkie za wyjaśnienia;)

Temat całkiem ciekawy. Znalazłem fajny przykład który mówi, że nawet na SELECT'ach w określonych wypadkach trzeba używać transakcji:
Cytat("za017")
Wyobraź sobie taką sytuację: dwie różne osoby odczytują z pewnej tabeli ilość dostępnych w sprzedaży przedmiotów i jednocześnie składają zamówienie na ostatnią sztukę: która z nich kupi ten przedmiot ? Transakcja uniemożliwia wystąpienie takiej sytuacji, przedmiot kupi ta osoba, która pierwsza uzyska (za pośrednictwem skryptu) dostęp do bazy danych.

W takiej sytuacji użycie transakcji jest jak najbardziej wskazane, nawet przy korzystaniu jedynie z select. gdyż pobrana z bazy danych zawartość może decydować o dalszym przebiegu wykonania skryptu, który może potem te dane modyfikować.
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.