Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Gotowa klasa do łączenia się z MYSQL przez PDO, MySQLi oraz MySQL
Forum PHP.pl > Forum > PHP
adrix88
Witam. Ostatnio zabrałem się za pisanie klasy do obsługi połączeń MySQL i poszukując inspiracji w sieci znalazłem dosyć ciekawą klasę do obsługi baz w której możemy wybierać typ połączenia PDO, MYSQLi lub MYSQL, tego w sumie potrzebowałem. Napiszcie co myślicie o tej klasie, jest waszym zdaniem dobrze napisana? Czy może znacie jakieś inne gotowe sprawdzone klasy?

LINK DO KLASY
Fifi209
Pisanie "nakładek" na mysql_ czy mysqli_ o pdo nie wspominając to kpina. wink.gif

Samo PDO udostępnia całkiem niezłą funkcjonalność, w wielu przypadkach wystarczy, nie miałem jeszcze przyjemności (lub nieprzyjemności) używać ORM.

Powiedz do czego Ci ta klasa? W celach edukacyjnych? Chcesz mogę Ci dać 10 innych tematów, na których możesz poćwiczyć obiektówkę.
zegarek84
Cytat(Fifi209 @ 23.06.2011, 23:19:23 ) *
Powiedz do czego Ci ta klasa?

choćby do większej uniwersalności kodu??

możesz mi nie wierzyć w to co teraz napiszę - sam byłem zaskoczony - ale jak jedną rzecz pisałem znajomemu okazało się, że nie mogę się połączyć z bazą mysql przez PDO gdzie ono było skompilowane o.O - z kolei jak druga mniejszą rzecz pisałem to już skorzystałem ze sqlite które tam można było utworzyć właśnie tylko przez PDO... wszystko zależy jak PHP na danym serwerze jest skompilowane...
adrix88
Generalnie chodzi mi właśnie o uniwersalność, żeby w każdym projekcie używać tej samej klasy do mysqla, a dodatkowym argumentem jest chęć przetestowania wydajności poszczególnych połączeń mysql na "żywym" organizmie, w różnych projektach. Wiele osób twierdzi że PDO jest wolniejsze od mysqli, natomiast jeszcze inni twierdzą że PDO jest szybkie w dużych aplikacjach, jak z tym jest tak naprawdę to nie wiem, ale chciałbym mieć możliwość przełączenia się pomiędzy tymi interfejsami.
zegarek84
do pojedynczego zapytania może i PDO wolniej wypadnie ale pomijając kwestię transakcji to w PDO możesz bindować zapytania SQL co jest z jednej strony bezpieczniejsze, z drugiej strony przy większej liczbie zapytań szybsze - oczywiście przy większej liczbie uaktualnień w bazie lepiej włączyć transakcje...

poza tym PDO masz wkompilowane w samo PHP - gdybyś wszystko to samo chciał zrobić to samo w samym PHP to napewno było by to wolniejsze ;]
Fifi209
Cytat(zegarek84 @ 23.06.2011, 23:44:41 ) *
choćby do większej uniwersalności kodu??

Wiesz jak to się mówi: jeżeli coś jest do wszystkiego to jest do niczego

Cytat(zegarek84 @ 24.06.2011, 00:00:16 ) *
z drugiej strony przy większej liczbie zapytań szybsze - oczywiście przy większej liczbie uaktualnień w bazie lepiej włączyć transakcje...

Co mają transakcje do szybkości?


Cytat(adrix88 @ 23.06.2011, 23:54:30 ) *
Generalnie chodzi mi właśnie o uniwersalność, żeby w każdym projekcie używać tej samej klasy do mysqla

Nic nie jest uniwersalne, nawet jeżeli napiszesz coś w miarę uniwersalnego, to i tak przy którymś projekcie będziesz musiał ją rozszerzać.
Cytat(adrix88 @ 23.06.2011, 23:54:30 ) *
, a dodatkowym argumentem jest chęć przetestowania wydajności poszczególnych połączeń mysql na "żywym" organizmie, w różnych projektach.

Wydajność zależy nie od samego PHP, dobre zaprojektowanie bazy danych, założenie odpowiednich indeksów. Poza tym, przy dzisiejszej mocy obliczeniowej procesorów - różnica rzędu 0.0001 sek nie będzie zauważalna nawet przy dużej liczbie odwiedzin.
adrix88
Widzę że dosyć dobrze ogarniacie PDO, bo ja to przyznam szczerze że dotychczas łączyłem się wyłącznie przez mysql. Mam do ciebie takie pytanie, nie wiem czy przeglądałeś tą klasę co podałem w temacie, ale zakładam że tak. Z tego co widzę to dane które dodawane są w zapytaniach mysql i mysqli są potraktowane funkcją mysql_escape_string, natomiast w przypadku w klasie z PDO brak jest tego filtrowania, hmm, czyli w tej klasie jest jakieś inne zabezpieczenie przed sql injected, czy też może brak w niej jakichkolwiek zabezpieczeń? Bo osobiście nie widzę tam niczego co mogłoby zabezpieczać przed tym atakiem, ale nie znam się na funkcjach PDO, więc mogę się mylić.
Spawnm
Masz bindowanie oraz execute wink.gif
zegarek84
Cytat(Fifi209 @ 24.06.2011, 00:08:08 ) *
Co mają transakcje do szybkości?

wgrywałeś/aktualizowałeś kiedyś co jakiś czas minimum po 3-5 tys. rekordów? - wiem - to bardziej od strony administracyjnej lub do jakichś tam narzędzi ale różnica nawet na lokalnym komputerze jest ;]
Fifi209
Transakcje

Tyle w temacie transakcji.
zegarek84
kiedy właśnie te minimum 3-5k rekordów minimum stanowi całość ;p [choć da się w sumie wgrać osobno a potem sprawdzić czy coś poszło nie tak - ale skoro to ma być razem to tylko wydłuży cały proces]

i pojedynczy insert bez włączenia transakcji też jest w obrębie ale własnej transakcji - gdy skożystasz z transakcji rozpoczęcie i zamkniecie jest wykonywane tylko raz ;p
Cytat(Wikipedia)
Transakcja składa się zawsze z 3 etapów:
  1. rozpoczęcia
  2. wykonania
  3. zamknięcia

tyle w temacie transakcji wink.gif
adrix88
Kurcze, porobiłem właśnie kilka zapytań PDO i muszę wam powiedzieć że te bindowanie jest strasznie niewygodne. Mam np. inserty po 60 pól i dla każdego z tych pól tworzyć bindy to jest przecież katorga, a to przecież tylko 1 zapytanie. Już wolę filtrowanie funkcją tak jak to robiłem w mysql, bo to co daje PDO to jakaś tragedia. Czy to filtrowanie od PDO jest naprawdę lepsze od poczciwego real_escape_string + stripslashes dla magic_quotes on?
Fifi209
Tak.
magic_quotes - oby zniknęło jak najprędzej, to zło, wystrzegaj się

Pisałem wcześniej o projektowaniu bazy danych, jesteś idealnym przykładem jak nie projektować bazy, 60 pól w tabeli? Chyba oszalałeś...

@zegarek
Przy 3-5k rekordów raczej skorzystałbym z poczciwego source lub chociaż load data niż bawił się w dodatkowych pośredników jak php.
adrix88
Fifi209, a co w tym złego że jest 60 pól w tabeli? chyba nie będę joinował kilka tabel żeby zmniejszyć liczbę pól w jednej tabeli. Jeżeli specyfikacja skryptu wymaga przechowywania tylu danych w tabeli to nawet żebyś był najlepszym programistą to tego nie przeskoczysz... Widziałeś w ogóle strukturę tabel np. w vBulletin'ie? W tym skrypcie są tabele grubo przekraczające liczbę pól którą podałem. Im większy projekt tym więcej danych i żebyś nie wiem jak chciał to tego nie przeskoczysz...
nospor
Cytat
Im większy projekt tym więcej danych i żebyś nie wiem jak chciał to tego nie przeskoczysz...
Wszystko zależy od projektu. Nie wiemy co tam u Ciebie było i czy te 60 pól było uzasadnione czy nie.

Cytat
Mam np. inserty po 60 pól i dla każdego z tych pól tworzyć bindy to jest przecież katorga, a to przecież tylko 1 zapytanie.
Może coś źle zrozumiałeś, może coś źle robisz, ale ja tam w bindowaniu nie widzę żadnej katorgi.

Cytat
Czy to filtrowanie od PDO jest naprawdę lepsze od poczciwego real_escape_string + stripslashes dla magic_quotes on?
Niby w czym bindowanie jest bardziej katorgą od używania real_escape_string + stripslashes? Chyba, naprawdę coś źle robiłeś wink.gif
Co do magic_quotes to fifi już napisał co należy z tym zrobić.
zegarek84
Cytat(Fifi209 @ 24.06.2011, 03:04:04 ) *
@zegarek
Przy 3-5k rekordów raczej skorzystałbym z poczciwego source lub chociaż load data niż bawił się w dodatkowych pośredników jak php.

fajnie się pisze - inna sprawa, że te dane pochodzą z innego programu i trzeba te dane z xml'a wyciągnąć ;]
Fifi209
zegarek, wiesz dla chcącego nic trudnego, o czym my tu dyskutujemy? Napisać program w C++ czy C#, który zapisze te dane w postaci CSV i wtedy load data...
Nie ciągnijmy już tego tematu, sposobów tyle co programistów. wink.gif
adrix88
Cytat(nospor @ 24.06.2011, 08:40:22 ) *
Wszystko zależy od projektu. Nie wiemy co tam u Ciebie było i czy te 60 pól było uzasadnione czy nie.


No tak. Tylko że akurat w tym projekcie te 60 pól jest raczej uzasadnione, ponieważ są tam przechowana id, nazwa, parametry danej usługi, data startu, data wygaśnięcia, cena. Więc akurat w tym przypadku nie widzę możliwości ograniczenia tych pól, bo każde z nich jest kluczowe.

Cytat(nospor @ 24.06.2011, 08:40:22 ) *
Może coś źle zrozumiałeś, może coś źle robisz, ale ja tam w bindowaniu nie widzę żadnej katorgi.


hm, robię to tak jak widać poniżej:

Dla zwykłego MySQL:

  1. $query = mysql_query("SELECT * FROM `tabela` WHERE `var1` = '".sql($_GET['var1'])." AND `var2` = '".sql($_GET['var2'])."' AND `var3` = '".sql($_GET['var3'])."'' AND `var4` = '".sql($_GET['var4'])."' ");


  1. while($dane = mysql_fetch_array($query)) {
  2. echo $dane['id'];
  3. echo $dane['nazwa'];
  4. }


Dla PDO:

  1. $query = $pdo->prepare('SELECT * FROM `tabela` WHERE
  2. `var1` = :var1 AND
  3. `var2` = :var2 AND
  4. `var3` = :var3 AND
  5. `var4` = :var4 ');
  6. $query->bindValue('var1', $_POST['var1'], PDO::PARAM_STR);
  7. $query->bindValue('var2', $_POST['var1'], PDO::PARAM_STR);
  8. $query->bindValue('var3', $_POST['var1'], PDO::PARAM_STR);
  9. $query->bindValue('var4', $_POST['var1'], PDO::PARAM_STR);
  10. $query->execute();
  11. $array = $query->fetchAll();


  1. foreach($arraye as $dane){
  2. echo $dane['id'];
  3. echo $dane['nazwa'];
  4. }


//////
Nie wiem czy robię wszystko poprawnie, ale na powyższych przykładach widać że tworzenie zapytań w mysql jest znacznie prostsze i szybsze oraz jest mniej kodu, a w PDO jednak trzeba się napisać ...

Cytat(nospor @ 24.06.2011, 08:40:22 ) *
Niby w czym bindowanie jest bardziej katorgą od używania real_escape_string + stripslashes? Chyba, naprawdę coś źle robiłeś wink.gif
Co do magic_quotes to fifi już napisał co należy z tym zrobić.

Robiłem to tak jak widać na przykładach powyżej, przecież nikt o zdrowych zmysłach nie używa samego real_escape_string na wartościach dodawanych w zapytaniu, do tego celu tworzy się funkcję czyszczącą która w przypadku gdy magic_quotes jest na on kasuje ukośniki przez stripslashes i następnie przemiela wartości przez real_escape_string. Wtedy tylko wywołuje się taką funkcję przy każdej zmiennej w zapytaniu np. sql($_GET['var']) i jest wszystko pięknie i przyjemnie. A jeżeli chodzi magic_quotes to wiem co z nim zrobić, chyba źle zrozumieliście mój post w którym o tym wspomniałem.

===============
Mam jeszcze do was takie pytanie, czy stosujecie jakieś nakładki na PDO, własne klasy obsługujące itd. czy korzystacie z tego standardowo bez żadnych nakładek? Bo z tego co czytałem kilka wypowiedzi z forum to nie ma sensu stosowanie własnych nakładek na PDO, chociaż osobiście nie do końca rozumiem dlaczego, co prawda nie znam jeszcze za dobrze tego typu połączenia z bazą, ale bo krótkiej zabawie, wydaje mi się że napisanie dodatkowej klasy obsługującej PDO ma sens i może przyśpieszyć pisanie kodu, ułatwić w przyszłości przejście na inny interfejs połączenia z bazą, a także daje możliwość dopisania funkcji liczących liczbę zapytań, ich czas, czy też zapisywanie wykonywanych zapytań itd. Chciałbym wiedzieć jaki jest wasz stosunek do tego. Korzystacie z własnych nakładek, czy to nie ma sensu i dlaczego?
zegarek84
Cytat(adrix88 @ 24.06.2011, 16:52:08 ) *
Nie wiem czy robię wszystko poprawnie, ale na powyższych przykładach widać że tworzenie zapytań w mysql jest znacznie prostsze i szybsze oraz jest mniej kodu, a w PDO jednak trzeba się napisać ...

na upartego przygotowane zapytanie nie musisz wcale bindować ;p - poczytaj w manualu PDOStatement->execute
a przede wszystkim zwróć uwagę na przykład drugi i trzeci:
http://pl2.php.net/manual/en/pdostatement....php#example-955

EDIT
Widzę, że źle bindujesz!!! Binduje się nazwy z dwukropkiem (poprzedzone nim) czyli np. :var1 lub jeśli masz znaki zapytania to kolejno przy bindowaniu numerujesz od 1 zaś dając tablicę do execute od 0 (co zresztą samo się ponumeruje nie ustawiając kluczy w tablicy)
thek
Znasz strukturę zapytania? Znasz. To w czym jest trudność zastosować:
  1. foreach( $_POST AS $key => $value) {
  2. $query->bindValue( $key, $value, PDO::PARAM_STR);
  3. }
lub czegoś w tym stylu po drobnych przeróbkach?
adrix88
Dzięki za odpowiedzi, są dla mnie bardzo pomocne.

@zegarek84, te powyższe przykłady pisałem z palca i po prostu wkradły się literówki, ale w moim testowych zapytaniach oczywiście są przed nazwami dwukropki, ale dzięki za czujność.

Jeżeli chodzi o ten przykład z execute to jest to dosyć ciekawe, ale z tego co czytałem to chyba nie jest to zbyt wydajne i zalecane. Sam nie wiem czy wybrać ten sposób.

@thek. bardzo ciekawy pomysł, ale dodatkowa pętla przy każdym zapytaniu to chyba mało wydajne rozwiązanie, przy jednym prostym zapytaniu to pewnie różnice są znikome, ale przy np. 100 zapytaniach w pętli to już myślę że może być problem i w takim wypadku już chyba szybsze będzie czyszczenie własną funkcją czyszczącą taką co używam w zwykłym mysql, nie sądzisz?

Chciałbym żebyście jeszcze się ustosunkowali do mojego ostatniego pytania w poprzednim poście:

Kod
Mam jeszcze do was takie pytanie, czy stosujecie jakieś nakładki na PDO, własne klasy obsługujące itd. czy korzystacie z tego standardowo bez żadnych nakładek? Bo z tego co czytałem kilka wypowiedzi z forum to nie ma sensu stosowanie własnych nakładek na PDO, chociaż osobiście nie do końca rozumiem dlaczego, co prawda nie znam jeszcze za dobrze tego typu połączenia z bazą, ale bo krótkiej zabawie, wydaje mi się że napisanie dodatkowej klasy obsługującej PDO ma sens i może przyśpieszyć pisanie kodu, ułatwić w przyszłości przejście na inny interfejs połączenia z bazą, a także daje możliwość dopisania funkcji liczących liczbę zapytań, ich czas, czy też zapisywanie wykonywanych zapytań itd. Chciałbym wiedzieć jaki jest wasz stosunek do tego. Korzystacie z własnych nakładek, czy to nie ma sensu i dlaczego?
Fifi209
Jeżeli wykonujesz 100 zapytań co odświeżenie to gratuluję. Już 60 pól mnie przeraża, nie możesz pokazać przypadkiem struktury bazy?
adrix88
Cytat(Fifi209 @ 24.06.2011, 18:44:36 ) *
Jeżeli wykonujesz 100 zapytań co odświeżenie to gratuluję. Już 60 pól mnie przeraża, nie możesz pokazać przypadkiem struktury bazy?


Proszę o to struktura jednej z tabel:
  1.  
  2. `serverid` int(10) NOT NULL AUTO_INCREMENT,
  3. `clientid` int(10) NOT NULL,
  4. `boxid` int(10) NOT NULL,
  5. `ipid` int(10) NOT NULL,
  6. `name` varchar(64) CHARACTER SET utf8 NOT NULL,
  7. `game` varchar(32) CHARACTER SET utf8 NOT NULL,
  8. `status` tinyint(1) NOT NULL,
  9. `query` varchar(10) COLLATE utf8_polish_ci NOT NULL,
  10. `location` tinyint(2) NOT NULL,
  11. `slots` tinyint(3) NOT NULL,
  12. `type` varchar(10) CHARACTER SET utf8 NOT NULL,
  13. `cfg1name` varchar(16) CHARACTER SET utf8 NOT NULL,
  14. `cfg1` varchar(16) CHARACTER SET utf8 NOT NULL,
  15. `cfg1edit` tinyint(1) NOT NULL,
  16. `cfg2name` varchar(16) CHARACTER SET utf8 NOT NULL,
  17. `cfg2` varchar(16) CHARACTER SET utf8 NOT NULL,
  18. `cfg2edit` tinyint(1) NOT NULL,
  19. `cfg3name` varchar(16) CHARACTER SET utf8 NOT NULL,
  20. `cfg3` varchar(16) CHARACTER SET utf8 NOT NULL,
  21. `cfg3edit` tinyint(1) NOT NULL,
  22. `cfg4name` varchar(16) CHARACTER SET utf8 NOT NULL,
  23. `cfg4` varchar(16) CHARACTER SET utf8 NOT NULL,
  24. `cfg4edit` tinyint(1) NOT NULL,
  25. `cfg5name` varchar(16) CHARACTER SET utf8 NOT NULL,
  26. `cfg5` varchar(16) CHARACTER SET utf8 NOT NULL,
  27. `cfg5edit` tinyint(1) NOT NULL,
  28. `cfg6name` varchar(16) CHARACTER SET utf8 NOT NULL,
  29. `cfg6` varchar(16) CHARACTER SET utf8 NOT NULL,
  30. `cfg6edit` tinyint(1) NOT NULL,
  31. `cfg7name` varchar(16) CHARACTER SET utf8 NOT NULL,
  32. `cfg7` varchar(16) CHARACTER SET utf8 NOT NULL,
  33. `cfg7edit` tinyint(1) NOT NULL,
  34. `cfg8name` varchar(16) CHARACTER SET utf8 NOT NULL,
  35. `cfg8` varchar(16) CHARACTER SET utf8 NOT NULL,
  36. `cfg8edit` tinyint(1) NOT NULL,
  37. `rcon` varchar(32) COLLATE utf8_polish_ci NOT NULL,
  38. `plusline` varchar(100) CHARACTER SET utf8 NOT NULL,
  39. `pluslineedit` tinyint(1) NOT NULL,
  40. `startline` text CHARACTER SET utf8 NOT NULL,
  41. `ftp_active` tinyint(1) NOT NULL,
  42. `webftp_active` tinyint(1) NOT NULL,
  43. `fd_active` tinyint(1) NOT NULL,
  44. `user` varchar(16) CHARACTER SET utf8 NOT NULL,
  45. `password` varchar(32) CHARACTER SET utf8 NOT NULL,
  46. `passftp` varchar(32) COLLATE utf8_polish_ci NOT NULL,
  47. `homedir` varchar(32) CHARACTER SET utf8 NOT NULL,
  48. `installdir` varchar(32) CHARACTER SET utf8 NOT NULL,
  49. `port` int(8) NOT NULL,
  50. `online` tinyint(1) NOT NULL,
  51. `okres_wykupu` varchar(40) COLLATE utf8_polish_ci NOT NULL,
  52. `cena` double DEFAULT NULL,
  53. `data_start` date NOT NULL,
  54. `data_koniec` date NOT NULL,
  55. `prices_id` tinyint(4) NOT NULL,
  56. `res_num` tinyint(1) NOT NULL,


Jeżeli chodzi o te 100 zapytań w pętli no to są dodawane informacje o statusie usług/maszyn co określony czas (taki system bieżącego monitorowania i zbierania statystyk), nie wiem jak inaczej byś to rozwiązał, uważam że w takim przypadku jest to koniecznośc
Crozin
@adrix88:
Wydajność, a tym bardziej czytelność kodu nie ma nic wspólnego z jego długością. Pętla, która działa na tablicy z 50 elementami ma w praktyce zerowy czas wykonywania nawet w takim powolnym języku jakim jest PHP. Największą zaletą Prepared Statements jest to, że w przeciwieństwie do normalnie* sklejanych zapytań wystarczy że zostaną one raz sparsowane i poddane optymalizacji przez serwer bazy danych. Chyba nie muszę tłumaczyć o ile mniej zasobów dzięki temu tracisz kosztem tych kilku znaków w kodzie.

* normalnie = "po staremu", bo to właśnie wykorzystanie PDO jest normalnym rozwiązaniem.

EDIT:
cfgX, cfgXname, cfgXedit - to mógłbyś wywalić do osobnej tabeli i utworzyć relację jeden-do-wielu, chyba że masz jakieś konkretne powody do przechowywania tego w jednej tabeli?
adrix88
No niby można je wrzucić do osobnej tabeli, ale nie wiem czy jest w tym jakiś sens, ponieważ te wartości są dosyć często wczytywane/edytowane wraz z pozostałymi i wtedy to raczej będzie miało więcej negatywnych skutków niż pozytywnych, ponieważ do wyświetlania/edycji kilku wartości trzeba będzie joinować tabele lub tworzyć po 2 zapytania, czy będzie to mieć jakiś pozytywny wpływ na wydajność bardzo bym zastanawiał, a jedynie ucierpi trochę czytelność bazy, bo jedna tabela będzie podzielona na 2 części. Moim zdaniem twoja rada to troszkę przerost formy nad treścią.
Crozin
Tak jak napisałem - jeżeli masz jakieś konkretne powody najlepiej poparte testami - bo "wydawanie się" bardzo często jest błędne - to nie ma żadnej dyskusji i taki schemat zostaje. Nie mam pojęcia jakie dane tam trzymasz ani co z nimi w ogóle robisz, więc ciężko mi powiedzieć czy jest to lepsze rozwiązanie. Zwróciłem Ci tutaj uwagę na to, ponieważ jest to konstrukcja nienaturalna dla tego typu bazy danych i w większości wypadków jedynie utrudnia, a nawet spowalnia pracę. Ale są również przypadki gdzie takie coś jest po prostu konieczne i jest korzystniejsze dla aplikacji. Czy tutaj jest taka sytuacja? Póki co nie da się tego określić (za mało informacji).
adrix88
Hmm, ale jaki będzie tu wzrost wydajności jeżeli praktycznie przy 70% zapytań te tabele będą musiały być łączone, przy zapisie i odczycie. Chciałbym też podkreślić że dane cfgXname cfgX i cfgXedit są to dane które dla każdej tabeli mogą być całkiem inne, żadna z tych wartości nie jest stała. Dlatego też myślę że lepszego rozwiązania w tym przypadku nie ma, ale oczywiście mogę być w błędzie.
Crozin
Jak już napisałem - nie mamy informacji by określić czy jest to lepsze. To, że w 70% tabele byłby łączone w sumie o niczym nie informuje, bo w tych przypadkach baza może mieć świetne osiągi, a w kolejnych 5% kompletnie się wykładać. By takie coś dało się określić musiałbyś podać wszystkie informacje począwszy od kompletnej struktury tabeli, poprzez przechowywane w niej dane po zapytania na niej wykonywane i ich częstotliwość. Musiałbyś mieć jeszcze kogoś komu chciałoby się to wszystko przeanalizować i przetestować. wink.gif
Ale nie to jest tematem wątku.


Jeszcze co do nakładek na PDO - oczywiście, że można z takich korzystać. Jeżeli nakładka taka udostępnia Ci coś czego PDO nie oferuje to jej użycie jest jak najbardziej uzasadnione. Tylko od razu uprzedzę, że nakładka która ma działać na zasadzie skrócenia zapisu z 120 do 104 znaków nie jest niczego warta.
Przykładem takiej nakładki może być chociażby Doctrine DBAL.
adrix88
Rozumiem. Chodzi mi bardziej żeby taka nakładka miała w sobie obsługę błędów, liczenie zapytań, czasu wykonywania zapytań.
Fifi209
Cytat(adrix88 @ 24.06.2011, 19:59:06 ) *
Chciałbym też podkreślić że dane cfgXname cfgX i cfgXedit są to dane które dla każdej tabeli mogą być całkiem inne

Miałeś na myśli wiersz?
Cytat(adrix88 @ 24.06.2011, 19:59:06 ) *
, żadna z tych wartości nie jest stała.

Skoro nie jest stała i się nie powtarzają jak sądzę to raczej nie ma sensu.

Poza tym cfg(x) moim zdaniem mógłbyś zapisywać w postaci tablicy ale to tylko moje domniemania bo nie wiem czy operujesz na tych danych po stronie bazy.

@edit
Co do obsługi błędów PDO rzuca ładnie wyjątkami, w czym problem?
adrix88
Właśnie chyba nie do końca rozumiem działanie tych wyjątków. We wszystkich przykładach pokazana jest mniej więcej taka struktura kodu przy zapytaniach:

  1. try
  2. {
  3. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  4. echo '<ul>';
  5. foreach($stmt as $row)
  6. {
  7. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  8. }
  9. $stmt -> closeCursor();
  10. echo '</ul>';
  11. }
  12. catch(PDOException $e)
  13. {
  14. echo 'Połączenie nie mogło zostać utworzone: '
  15. }


Powyższy przykład wydaje się bardzo niewygodny, ponieważ za każdym razem trzeba wywoływać bloki TRY. Nie można by tak zamykać całej strony w jednym wielkim bloku TRY? np. coś takiego:

  1. try
  2. {
  3. require('jakiesfunkcje.php');
  4. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  5. echo '<ul>';
  6. foreach($stmt as $row)
  7. {
  8. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  9. }
  10. $stmt -> closeCursor();
  11. echo '</ul>';
  12.  
  13. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  14. echo '<ul>';
  15. foreach($stmt as $row)
  16. {
  17. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  18. }
  19. $stmt -> closeCursor();
  20. echo '</ul>';
  21.  
  22. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  23. echo '<ul>';
  24. foreach($stmt as $row)
  25. {
  26. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  27. }
  28. $stmt -> closeCursor();
  29. echo '</ul>';
  30. require('szablon_strony.php');
  31. }
  32. catch(PDOException $e)
  33. {
  34. echo 'Połączenie nie mogło zostać utworzone: '
  35. }


Czy powyższy kod będzie spełniać swoją funkcję i jest to poprawne rozwiązanie? Czy jednak muszę każde zapytanie ładować w oddzielny blok?
Crozin
Podstawowa zasada związana z wyjątkami: przechwytujesz je tylko i wyłącznie wtedy gdy możesz z nimi coś sensownego zrobić.
Jak najbardziej możesz objąć cały kod aplikacji blokiem try .. catch. Pamiętaj, że bloki mogą być dowolnie zagnieżdżone.
Fifi209
Swoją drogą w przykładach powinno być bardziej:

  1. try {
  2.  
  3. // kod
  4.  
  5. }catch(PDOException $e) {
  6. echo $e->getMessage();
  7. }
adrix88
Czyli rozumiem że nie ma różnicy czy utworzę 30 bloków try .. catch, czy jeden duży, wszystkie błędy będą i tak przekazywane. Tak?
Crozin
Rozumiem pytasz czy jest jakaś różnica pomiędzy
  1. try
  2. {
  3. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  4. echo '<ul>';
  5. foreach($stmt as $row)
  6. {
  7. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  8. }
  9. $stmt -> closeCursor();
  10. echo '</ul>';
  11. }
  12. catch(PDOException $e)
  13. {
  14. echo 'Połączenie nie mogło zostać utworzone: '
  15. }
  16.  
  17. try
  18. {
  19. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  20. echo '<ul>';
  21. foreach($stmt as $row)
  22. {
  23. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  24. }
  25. $stmt -> closeCursor();
  26. echo '</ul>';
  27. }
  28. catch(PDOException $e)
  29. {
  30. echo 'Połączenie nie mogło zostać utworzone: '
  31. }
  32.  
  33. try
  34. {
  35. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  36. echo '<ul>';
  37. foreach($stmt as $row)
  38. {
  39. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  40. }
  41. $stmt -> closeCursor();
  42. echo '</ul>';
  43. }
  44. catch(PDOException $e)
  45. {
  46. echo 'Połączenie nie mogło zostać utworzone: '
  47. }
Oraz
  1. try
  2. {
  3. require('jakiesfunkcje.php');
  4. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  5. echo '<ul>';
  6. foreach($stmt as $row)
  7. {
  8. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  9. }
  10. $stmt -> closeCursor();
  11. echo '</ul>';
  12.  
  13. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  14. echo '<ul>';
  15. foreach($stmt as $row)
  16. {
  17. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  18. }
  19. $stmt -> closeCursor();
  20. echo '</ul>';
  21.  
  22. $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
  23. echo '<ul>';
  24. foreach($stmt as $row)
  25. {
  26. echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
  27. }
  28. $stmt -> closeCursor();
  29. echo '</ul>';
  30. require('szablon_strony.php');
  31. }
  32. catch(PDOException $e)
  33. {
  34. echo 'Połączenie nie mogło zostać utworzone: '
  35. }


Wystąpienie wyjątku powoduje przerwanie wykonywania bloku TRY i natychmiastowe przeskoczenie do pierwszego pasującego bloku CATCH, tak więc w pierwszym przypadku jeżeli pierwsze zapytanie wyrzuci wyjątek skrypt przeskoczy do bloku CATCH (pierwszego) wykona go po czym będzie kontynuować swoje działanie, czyli natrafi na drugi blok TRY itd. Natomiast w drugim przypadku jeżeli pierwsze zapytanie wyrzuci wyjątek skrypt przejdzie do bloku CATCH, wykona go po czym będzie próbował działać dalej - w tym przypadku zakończy swoje działanie, bo dalej nie ma już niczego do wykonywania.

Wyjątki są jako tako opisane w dokumentacji języka: http://php.net/manual/en/language.exceptions.php
adrix88
Super. Dzięki wielkie, właśnie o taką odpowiedź mi chodziło.
zegarek84
ale wizulanie lepiej by to wyglądało porównanie
Kod
forech(...){
   try{...} catche(...){...}
}

vs
Kod
try{
   foreach(...){...}
} catche(...){}

i adekwatnie pierwszy do pierwszego (przecież nikt nie będzie ręcznie powtażał 20 razy tego samego kodu) drugi do drugiego... i jak już Crozin napisał w pierwszym przypadku pętla wykona się tyle razy ile ma się wykonać i spróbuje zrobić to co jest wewnątrz niej, w drugim przypadku pętla albo cała/fragment/lub raz się wykona jeśli błąd wystąpi to nastąpi przerwanie jej wykonywania...

plusem bloków try catche jest to, że reszta skryptu będzie chodziła i jeśli coś poszło nie po myśli to to sobie po prostu obsłużysz...
thek
@adrix88: Odniosę się tylko do samej pętli, o której wspomniałem. Zauważ, że chcąc - nie chcąc i ta to robisz smile.gif Różnica jest tylko w zapisie.
Albo puszczasz w pętli takiej jak ja przedstawiłem mniej więcej, albo robisz tyle instrukcji bindowania ile masz parametrów dla jawnego odwołania w PDO. A teraz niby walnięcie tych kilkudziesięciu parametrów w mysql_real_escape_string dla czystego odwołania funkcjami mysql_* miałoby utworzyć krótsze zapytanie?

Ja, nieważne czy używam pdo czy mysql_* to i tak trzymam wszystkie dane mające iść do bazy w tablicy i tylko potem lecę w pętli z escape'owaniem lub bindowaniem. Oszczędzam wieeeeele linijek kodu lub pisania kosmicznie długiego zapytania z jawnym wywołaniem funkcji mysql_real_escape_string dla każdej wartości. Narzut czasowy tak naprawdę jest nieznaczny, za to czytelność i prostota kodu są nieporównywalne.

Inna sprawa, że dla mnie zapytanie puszczone w pętli sugeruje, iż spaprałem strukturę tabel wink.gif W najcięższych przeze mnie stworzonych projektach do wygenerowania całej strony zazwyczaj nie przekraczam liczby 10 zapytań wink.gif Czasem są one długie i mają wiele joinów, ale elastyczność tabel sprawia, że dodawanie nowych funkcjonalności to po prostu pikuś. A tak patrząc na strukturę tabeli jaką dałeś, to domyślam się, że to tabela o nazwie "Product" i z marszu mogę powiedzieć, że bez problemu bym pewnie ją na dwie lub trzy rozbił. Czemu? Bo na bank i tak za każdym razem nie wykorzystujesz wszystkich danych. Pewne zapytania najczęściej używane pobierają tylko określone kolumny a reszta i tak leży odłogiem czekając na bardziej specjalizowane żądania. Myślisz, że wydajniejsze dla bazy jest przelatywanie prze jedną tabelę z 60 kolumnami po to by wybrać tylko 10 kolumn w 90% przypadków czy podzielić tę tabelę na dwie, z których jedna będzie dokładnie te 10 kolumn zawierać, zaś druga pozostałe + id? Jakoś nie wierzę, że uprawnienia konfiguracyjne związane z edycją są przy byle prostym wyświetlaniu konieczne do pobrania i sprawdzania smile.gif Ogólnie jednak zgadzam się z Crozinem - wszystko zależy od tego JAK pracujesz z bazą, jakie zapytania doń idą. Najczęściej jednak taka ilość kolumn sugeruje, że coś nie tak jest i warto pomyśleć o optymalizacjach struktury.
adrix88
Hm.. No tak, tylko że mając na myśli zapytania w pętli miałem tu na myśli zapytania INSERT, które dodają do bazy np. co określony czas informacje o statusie usługi oraz zbierają statystyki obciążenia, a tego niestety nie da się inaczej zrobić jeżeli potrzebny jest bieżący monitoring takich danych jak obciążenie, wykorzystanie procesora, pamięci dla danego procesu na maszynie itd. Takich rzeczy nie załatwisz inaczej nić crobtab i wykonywanie pętli z insertami co określony czas (zresztą ja nie widzę tu żadnego bardziej sensownego rozwiązania).

Jeżeli chodzi o liczbę pól, to czy naprawdę jest ich aż tak dużo? Naprawdę podzielenie tego na mniejsze tabele i joinowanie wszystkiego przy selectach, insertach, updejtach da tu jakikolwiek wzrost wydajności? Na logikę biorąc to jedynie może obniżyć wydajność, bo przecież np. przy zwykłym SELECTcie są w jednym czasie wczytywana dwie tabele, muszą być odczytane dwa indexy, a następnie są one razem łączone w całość. Natomiast aktualnie przecież leci prosty SELECT bez żadnych JOINów i są wyświetlane te same dane. Nie wiem, może i słabo ogarniam mysql'a, no ale logika mi mówi że rozwiązanie które mi podsuwasz nie jest wcale lepsze, a jedynie dodaje masę niepotrzebnej roboty dla mnie oraz mysqla.
Crozin
Od razu chciałbym uprzedzić że wszystko co jest napisane poniżej oparte jest o - niestety - bardzo małą wiedzę z zakresu przechowywania i przetwarzania danych, tak więc całkiem możliwym jest, że trochę bzdur może się tutaj znaleźć.
Przy okazji zaznaczę jeszcze raz, że ani ja, ani thek, ani ktokolwiek inny w tym wątku nie mamy najmniejszego pojęcia jakie dokładnie dane przechowujesz, co potrzebujesz z nimi robić,i jak często, czy dałoby się to jakoś zoptymalizować itd. Dlatego też nie padnie tutaj stwierdzenie, że "masz źle" bo nie mamy pojęcia czy to co masz jest dobre czy złe. Konieczne byłoby wykonanie testów żeby to potwierdzić albo ktoś kto już w przeszłości zmagał się z czymś podobnym i z doświadczenia może się wypowiedzieć. wink.gif

Jak generalnie dobrze zauważyłeś podzielenie tego na mniejsze tabele, gdzie każda odpowiedzialna jest za reprezentowanie jakiś poszczególnych "elementów" tej całości niesie za sobą konieczność dodatkowej pracy dla silnika bazy danych. Jednakże może - bo jak już wspomniałem nie wiemy co Ty tam dokładnie robisz - również odciążyć go z całej masy roboty związanej ze "skakaniem" po dysku. Pamiętaj że dane zapisane są niejako ciurkiem i komputer nie może tak od odczytać sobie zawartości kolumny "passftp". Musi najpierw dojść do tego który fragment z serii zer i jedynek to wartość tej kolumny. Niestety w tej tabeli większość kolumn ma zmienną długość a więc konieczne będzie odczytanie długości wszystkich kolumn. Innymi słowy zakładając, że dane są zapisane na dysku w takiej kolejności jak w strukturze tabeli:
1. Ustawiamy się na początku rekordu.
2. Skaczemy o 16 bajtów (4 x INT)
3. Odczytujemy długość kolumny "name"
4. Skaczemy o długość kolumny "name"
5. Odczytujemy długość kolumny "game"
6. Skaczemy o długość kolumny "game"
...
91. Skaczemy o długość kolumny "password"
92. Odczytujemy długość kolumny "passftp"
93. W końcu odczytujemy zawartość kolumny "passftp"
Jak widzisz trochę operacji trzeba wykonać, i tak dla każdego jednego rekordu z osobna. Trzeba pamiętać o tym, że operacje dyskowe są często tym wąskim gardłem w prędkości działania aplikacji.

Nie wiem czy MySQL działa w dokładnie taki sposób - fajnie jakby ktoś bardziej obeznany mógł się wypowiedzieć - ale stawiam, że jednak będzie to coś w ten deseń.
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.