Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Łapanie wyątków z baz danych
Forum PHP.pl > Forum > PHP
tadeurz
Witam mam kolejne pytanie.
Komunikując się z jakąkolwiek bazą danych używamy driverów, one są tak genialne że wyrzucają nam wyjątki. Rozchodzi mi się o sens wyłapywania wyjątku przy każdym zapytaniu. Po dłuższym zastanowieniu doszedłem do wniosku, że to nie ma sensu. W przykładach posłużę się MongoDB.
  1. //w ciele wrappera/adaptera mamy utworzenie klienta
  2. Try{
  3. $this->db = new MongoClient();
  4. }catchMongoConnectionException $e){
  5. ...
  6. }
  7. //gdzieś w kodzie
  8. //pobieramy gdzieś listę użytkowników
  9. Try{
  10. $usersCursor = $this->db->myDB->collections->find()
  11. }catch(MongoCursorException $e){
  12. ...
  13. }
  14. //chcemy pobrać informacje na temat użytkownika
  15. Try{
  16. $query = array(_ID=>$player);
  17. $usersCursor = $this->db->myDB->collections->findOne($query)
  18. }catch(MongoCursorException $e){
  19. ...
  20. }

Takie łapanie błędów ma sens tylko w fazie debugowania jeżeli zapytanie nie działa tak jak chcemy. Jeżeli nasze zapytanie zadziała raz, to nie ma szans, żeby nagle przestało działać i wyrzucać wyjątki. Dlatego jedynym miejscem gdzie wystarczy złapać wyjątek jest:
  1. Try{
  2. $this->db = new MongoClient();
  3. }catchMongoConnectionException $e){
  4. ...
  5. }


Mylę się?
phpion
Cytat(tadeurz @ 9.08.2013, 10:20:22 ) *
Jeżeli nasze zapytanie zadziała raz, to nie ma szans, żeby nagle przestało działać i wyrzucać wyjątki.

No nie do końca. W przypadku większości SELECTów czy DELETów pewnie tak będzie (pomijając SQL Injection mogące spowodować błąd), ale np. INSERTy czy UPDATy mogą czasem nie przejść (błąd klucza obcego, dane przekraczające zakres pola itd.).
sowiq
Cytat(tadeurz @ 9.08.2013, 10:20:22 ) *
Jeżeli nasze zapytanie zadziała raz, to nie ma szans, żeby nagle przestało działać i wyrzucać wyjątki.

Mylę się?


Ano mylisz. Są różne sytuacje, które mogą wystąpić nawet jeśli przy testowaniu było wszystko OK:
- serwer bazy danych padnie w czasie wykonywania skryptu
- coś będzie nie tak z danymi w zapytaniu (np. NULL na pole, które jest NOT NULL)
- zaburzy się spójność danych (np. ktoś doda komentarz do artykułu, który ktoś inny w międzyczasie usunie)
itd.

Wyjątki są po to, żeby z nich korzystać smile.gif
Crozin
Mylisz się co do tego gdzie może pojawić się wyjątek co już Ci napisano. Masz jednak rację co do tego, że łapanie wyjątków wszędzie, gdzie to tylko możliwe jest bez sensu. Wyjątki łapiemy dopiero wtedy, kiedy możemy z nimi coś sensownego zrobić. W przypadku błędów wynikających z pracy sterownika bazy danych niemal zawsze jedynym co możemy zrobić to wyświetlić komunikat 500 Internal Server Error i co najwyżej jawnie cofnąć wszystkie otwarte transakcje. Dlatego spokojnie możesz utworzyć sobie blok try..catch w jakimś centralnym miejscu, w którym startuje aplikacja i tam przechwytywać wszystkie niewychwycone wyjątki w celu "kontrolowanego wywalenia strony".
tadeurz
Nie zgodzę się z wami. Wszystko zależy też od tego jak to zakodujemy (i od tego jak stosujemy wyjątki, i jak one powinny być stosowane. Ale jest to temat na który każdy programista ma inne zdanie. Jest wiele tematów na ten temat więc nie poruszajmy tej kwestii)
Dlatego jeżeli raz zaprojektujemy zapytanie to ono nigdy nie wyrzuci wyjątku(*):
  1. $var->check($email) //funkcja która nam sprawdza czy email jest poprawny, w przeciwnym wypadku nawet nie idzie dalej.
  2. // tutaj ważna rzecz o której piszecie czyli złych danych (typach, przedziałach itp.)
  3. //ja w swoich projektach nie pozwalam żeby do zapytania przeszło coś co miało być liczbą a jest stringiem
  4. //jeżeli jakieś pole jest opcjonalne, to n poziomie bazy danych ustawiam default value NULL (jako że w mongoDB są dokumenty których struktura może się różnić nawet tego pola nie dodaje.)
  5. If ( $pole = $var->check($_POST[‘pole’]) ) $update[‘pole’] = $pole;
  6. If ( $pole1 = $var->check($_POST[‘pole1’]) ) $update[‘pole1’] = $pole1;
  7. //po czymś takim niemożliwe jest w zapytaniu okazało się że pole jest puste
  8. $query = array(_id: $email)
  9. $fields=array(‘$set’=>$update);
  10. If( $this->db->myDB->collection->update($query,$fields) ) //jeśli wykona TRUE, jeśli nie FALSE
  11. //jeżeli dane będą niespójne to zwróci FALSE = nie wykonałem zapytania



*Wyrzuci wyjątek tylko i tylko wtedy gdy jak pisaliście baza padnie W CZASIE wykonywania skryptu, czyli akurat wstrzeli się w setne sekundy, to nie jest ironia BO: dla milionów wyświetleń I can be happen. Crozin napisał co z tym trzeba zrobić (globalny blok try). Jeśli mamy jakiegoś adaptera przez który przechodzą zapytania to on jest dobrym miejscem na tego typu blok.
Crozin
Tak jak napisałeś dobrym miejscem na umieszczenie bloku try..catch, będzie właśnie taki adapter. Przy czym warto zwrócić tutaj uwagę na to, że i tak prawdopodobnie wyjątek tam przechwycony zostanie wyrzucony dalej.

Jednak chciałem tutaj zwrócić uwagę na coś innego. Źle zakładasz, że jeżeli sprawdzisz poprawność danych wykonanie zapytania nie będzie mogło wyrzucić wyjątku: będzie mogło. I nie chodzi nawet o to, że baza danych sama z siebie padnie w trakcie wykonywania skryptu. Wysypać się może cała rzesza innych rzeczy. Wystarczy spojrzeć na standardową listę błędów MySQL-a czy Postgresa (wiele z tych błędów może wystąpić przy kompletnie różnych operacjach) by zobaczyć ile tego jest. A to tylko fragment dotyczący bezpośrednio bazy danych, sterownik połączenia może wywalić jeszcze drugie tyle (jak nie więcej). Co istotniejsze, wiele błędów może wyniknąć dopiero w czasie działania aplikacji, w momencie gdy jakieś dane, które powinny być poprawne są jednak niepoprawne. I wcale błąd nie musi płynąć bezpośrednio z zapytania SQL - może go wywołać jakiś wyzwalacz czy funkcja/procedura.

Podsumowując: wyjątków SQL-a czy ogólnie bazy danych nie ma najczęściej sensu łapać, bo gdy taki wystąpi i tak powinniśmy przerwać działanie aplikacji.
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.