Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: PDO i zamykanie połączenia ?
Forum PHP.pl > Forum > PHP
Mayka
Witam, chciałem zapytać czy jest jakieś polecenie/wywołanie do zamknięcia połączenia przy PDO i mysql ?
  1. function dbInit(){
  2. $dbs=new PDO('mysql:host='.$DBVARS['hostname'].';port='.$DBVARS['port'].';dbname='.$DBVARS['db_name'],$DBVARS['username'],$DBVARS['password']);
  3. $dbs->query('SET NAMES utf8');
  4. $dbs->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  5. $dbs->num_queries=0;
  6. $GLOBALS['db']=$dbs;
  7. return $dbs;
  8. }
  9. function dbQuery($query){
  10. $dbs=dbInit();
  11. $q=$dbs->query($query);
  12. $dbs->num_queries++;
  13. return $q;
  14. }
  15. function dbRows($query) {
  16. $q = dbQuery($query);
  17. //print_r($dbs->errorInfo());
  18. return $q->fetchAll(PDO::FETCH_ASSOC);
  19. }


Znalazłem takie coś w skryptach/książkach, i bardzo ciekawie się to sprawdza tylko że niestety niewiem czemu generuje to 25tyś połączeń przy 20użytkownikach.. Czy ktoś jest mi wstanie pomóc/ przerobić to tak żeby nie było połączenia/inicjacji bazy przy każdym dbQuery() ? Ew czy to można jakoś zamknąć ?
Mayka
tzn mam dołożyć $dbs->closeCursor(); ?
Methestel
Radzę w ogóle zmienić podejście i ten antypattern zamienic na coś rozsądniejszego np:

  1. <?php
  2. class PdoFactory {
  3. private static $pdoInstances = array();
  4.  
  5. private function __construct() {}
  6.  
  7. /**
  8. * @param string $key
  9. * @throws PDOException
  10. * @throws Exception
  11. */
  12. private static function set($key = null) {
  13. try {
  14. //Tutaj wstaw fragment kodu ktory ustawi odpowiednie wartosci dla $dsn, $user, $password
  15.  
  16. $pdo = new PDO($dsn, $user, $password);
  17. $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
  18. $pdo->setAttribute( PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
  19. self::$pdoInstances[$key] = $pdo;
  20. } catch (PDOException $e) {
  21. echo 'Connection failed: '.$e->getMessage();
  22. throw $e;
  23. } catch (Exception $e) {
  24. echo $e->getMessage();
  25. throw $e;
  26. }
  27. }
  28.  
  29. /**
  30. * @param string $key
  31. * @return PDO
  32. */
  33. public static function get($key) {
  34. if (!isset(self::$pdoInstances[$key])) {
  35. self::set($key);
  36. }
  37. return self::$pdoInstances[$key];
  38. }
  39.  
  40. public static function closeAll() {
  41. foreach ( self::$pdoInstances as $key => $pdo ) {
  42. self::$pdoInstances[$key] = null;
  43. }
  44. }
  45. }
  46. ?>


Obiekt klasy PDO pobierasz przez PdoFactory::get('nazwaPolaczenia');
Jeśli korzystasz tylko z jednej bazy danych możesz zmodyfikować skrypt tak żeby nie trzeba było podawać w ogóle parametru do metody PdoFactory::get()
Przed zakończeniem skryptu lub w momencie kiedy jesteś pewien że nie będziesz już potrzebował komunikacji z bazą danych pamiętaj o wywołaniu PdoFactory::closeAll()
Mayka
A mogłbyś jeszcze powiedzieć jak teraz przez to pobrać dane ?
!*!
Zamiast tworzyć jakieś bzdurne klasy korzystaj z PDO takim jakie jest. http://pl.wikibooks.org/wiki/PHP/Biblioteka_PDO
Methestel
Trzymając się kodu z pierwszego posta i wykorztując klasę PdoFactory którą Ci podałem mogłoby wyglądać to np tak:

  1. function dbQuery($query){
  2. $dbs=PdoFactory::get('identyfikatorPołączenia');
  3. //lub $dbs=PdoFactory::get(); - w zależności czy chcesz obsługiwać kilka połączeń czy tylko jedno
  4. $q=$dbs->query($query);
  5. $dbs->num_queries++;
  6. return $q;
  7. }
  8. function dbRows($query) {
  9. $q = dbQuery($query);
  10. //print_r($dbs->errorInfo());
  11. return $q->fetchAll();
  12. }


Funkcja dbInit() nie jest Ci już potrzebna. Obiekty klasy PDO pobierasz teraz używając klasy PdoFactory. Zaletą tego jest to że PdoFactory::get() nie będzie łączyć się za każdym razem z bazą danych. Zrobi to raz a potem będzie już zwracane wcześniej utworzony obiekt klasy PDO.
Mayka
Cytat(!*! @ 10.12.2013, 10:46:15 ) *
Zamiast tworzyć jakieś bzdurne klasy korzystaj z PDO takim jakie jest. http://pl.wikibooks.org/wiki/PHP/Biblioteka_PDO


Widziałem tą strone, tylko że $stmt -> closeCursor(); które tutaj jest podane powoduje u mnie błąd Call to undefined method PDO::closeCursor() '


@Methestel
To zwykłe pdo nie potrafi zrobić jednego połączenia ?

Znalazłem coś takiego:
$dbs->db = null;

Czy jak wstawie takie coś do dbquery i dbrows na koniec to połączenie zostanie zamknięte po każdym wczytaniu/zmianie ?
Damonsson
Po co Ci to manualne zamykanie połączenia?

Jak już to $dbs = null;
Methestel
Zwykłe PDO jak najbardziej potrafi zrobić jedno połączenie. Tylko chodzi o to żeby nie robił tych połączeń przy każdym zapytaniu tylko maksymalnie raz podczas jednego requesta. Nie wiem jak to prościej wyjaśnić ... może wyobraź sobie że masz do wykonania 100 zapytań do bazy danych.
Masz do wyboru:
- przed każdym zapytaniem tworzysz nowe połączenie z bazą danych i wykonujesz zapytanie (łącznie wykonujesz 100 połączeń z bazą danych i 100 zapytań)
- tworzysz jedno połączenie z bazą danych i używając tylko tego jednego połączenia wykonujesz kolejno 100 zapytań (łącznie 1 połączenie z bazą danych i 100 zapytań)

Efekt końcowy będzie taki sam. Jak myślisz, które rozwiązanie jest lepsze?


Tak, jak wstawisz $dbs = null na koniec dbquery to połączenia będą zamykane - zresztą masz to jak wół napisane w dokumentacji http://www.php.net/manual/en/pdo.connections.php
Jeśli nie przeszkadza Ci że przy każdym zapytaniu będziesz od nowa łączył się z bazą danych to nie ma problemu.
ctom
tak jak napisał @Methestel problemem w Twoim skrypcie nie jest zamykanie połączeń ale ich nadmierne "otwieranie" - a podejrzewam, że Twoim jest to
Turson
Jeśli przy każdym zapytaniu nawiązujesz połączenie z bazą przez dbInit() to jest bezsensu. Jak piszesz w OOP to w konstruktorze nawiązujesz połączenie z bazą i później tylko się odwołujesz przez np. $this->db, albo tworzysz instancję new PDO i działasz na tym w całym dokumencie.
Mayka
Cytat(Turson @ 10.12.2013, 22:44:25 ) *
Jeśli przy każdym zapytaniu nawiązujesz połączenie z bazą przez dbInit() to jest bezsensu. Jak piszesz w OOP to w konstruktorze nawiązujesz połączenie z bazą i później tylko się odwołujesz przez np. $this->db, albo tworzysz instancję new PDO i działasz na tym w całym dokumencie.


A jak nie pisze w oop ?
To jak to zrobić żeby połączenie było raz wykonywane a nie przy każdym requescie ?

Cytat(Methestel @ 10.12.2013, 20:24:07 ) *
Tak, jak wstawisz $dbs = null na koniec dbquery to połączenia będą zamykane - zresztą masz to jak wół napisane w dokumentacji http://www.php.net/manual/en/pdo.connections.php
Jeśli nie przeszkadza Ci że przy każdym zapytaniu będziesz od nowa łączył się z bazą danych to nie ma problemu.


A czemu ma mi to przeszkadzać bo nie rozumiem ?
ctom
Cytat(Mayka @ 11.12.2013, 17:12:25 ) *
To jak to zrobić żeby połączenie było raz wykonywane a nie przy każdym requescie ?


przecież @Methestel Ci napisał jak tu

Cytat(Mayka @ 11.12.2013, 17:12:25 ) *
Cytat(Mayka)

Jeśli nie przeszkadza Ci że przy każdym zapytaniu będziesz od nowa łączył się z bazą danych to nie ma problemu.


A czemu ma mi to przeszkadzać bo nie rozumiem ?


może twój serwer będzie miał coś przeciwko ;-) ? pewnie masz apache , to zrób sobie test wydajności twojego rozwiązania i tego z jednym inicjowanym połączeniem (np. ab -n 1000 -c 10 )
Methestel
Sama się pytasz w pierwszym poście jak zrobić "żeby nie było połączenia/inicjacji bazy przy każdym dbQuery()" a teraz pytasz dlaczego łączenie się z bazą przy każdym zapytaniu ma Ci przeszkadzć :/

Sorry ale ja się poddaje.
Mayka
Cytat(Methestel @ 11.12.2013, 17:31:54 ) *
Sam się pytasz w pierwszym poście jak zrobić "żeby nie było połączenia/inicjacji bazy przy każdym dbQuery()" a teraz pytasz dlaczego łączenie się z bazą przy każdym zapytaniu ma Ci przeszkadzć :/

Sorry ale ja się poddaje.


Hahaha, chodziło mi bardziej o to, że teraz wiem jak je rozłączyć wiec moge przy każdym pobraniu rozłączyć z bazą i wtedy nie bedzie przekroczenia ilości jednoczesnych połączeń.

Cytat(ctom @ 11.12.2013, 17:30:54 ) *
przecież @Methestel Ci napisał jak tu



A czemu ma mi to przeszkadzać bo nie rozumiem ?


może twój serwer będzie miał coś przeciwko ;-) ? pewnie masz apache , to zrób sobie test wydajności twojego rozwiązania i tego z jednym inicjowanym połączeniem (np. ab -n 1000 -c 10 )

Nie zrobie bo niemam dostępu do tego serwera -zwykły hosting w nazwie.
Turson
Cytat(Turson @ 10.12.2013, 22:44:25 ) *
tworzysz instancję new PDO i działasz na tym w całym dokumencie.

Mayka
Cytat(ctom @ 11.12.2013, 17:30:54 ) *
przecież @Methestel Ci napisał jak tu


Czyli dobrze rozumiem że trzeba zrobić to w oop bo inaczej bedzie za każdym dbquery łączył z baza ?

Aha i PdoFactory::closeAll() na samym końcu strony tak ?
Turson
Żadne OOP.
  1. $db = new PDO('mysql:host=;dbname=', '', '', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'")) or die();

Dalej już wszystkimi zapytaniami operujesz na $db, np. $db->query(...)
ctom
powiedz szczerze, nie masz pojęcia co ta klasa PdoFactory robi ?

a z ciekawości po co robisz to Twoje dbquery questionmark.gif wstaw więcej kodu jak możesz
Mayka
Cytat(ctom @ 11.12.2013, 18:11:50 ) *
powiedz szczerze, nie masz pojęcia co ta klasa PdoFactory robi ?

a z ciekawości po co robisz to Twoje dbquery questionmark.gif wstaw więcej kodu jak możesz



No klasa pdoFactory jest do łączenia z baza, tylko że niewiem jaka różnica jest miedzy tym co ja mam a tym co jest w klasie ? I po co to pakować do oop ?
A dbquery wykorzystuje do wstawiania elementów do bazy..

a w takim razie jeszcze inaczej skoro mam odwołanie do zmiennych globalnych w dbinit - $GLOBALS['db']=$dbs; to czy nie można zrobić tak że w skrypcie na początku robie initdb i korzystać w dbquery z tego ? znaczy tak:
  1. function dbInit(){
  2. if(isset($GLOBALS['dbs']))return $GLOBALS['dbs'];
  3. global $DBVARS;
  4. $dbs=new PDO('mysql:host='.$DBVARS['hostname'].';port='.$DBVARS['port'].';dbname='.$DBVARS['db_name'],$DBVARS['username'],$DBVARS['password']);
  5. $dbs->query('SET NAMES utf8');
  6. $dbs->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  7. $dbs->num_queries=0;
  8. $GLOBALS['db']=$dbs;
  9. return $dbs;
  10. }
  11. function dbQuery($query){
  12. $q=$GLOBALS['db']->query($query);
  13. $GLOBALS['db']->num_queries++;
  14. return $q;
  15. }
  16. function dbRows($query) {
  17. $q = dbQuery($query);
  18. return $q->fetchAll(PDO::FETCH_ASSOC);
  19. }

i dbinit() wstawiłem do indexu w pierwsza linijke, czy teraz jest ok ?
ctom
założę się, że i tak masz wszystko w tym pliku index .... po co PDO opakowujesz w te funkcje questionmark.gif

może tak.... to jakbyś kupił dziewczynie wibrator i kazała jej używać go tylko w prezerwatywie - można, tylko po co :-)
Mayka
Cytat(ctom @ 11.12.2013, 19:14:07 ) *
założę się, że i tak masz wszystko w tym pliku index .... po co PDO opakowujesz w te funkcje questionmark.gif

No i byś przegrał wink.gif Narazie sie bawie, ale jak sam potrafiłem zapchać połączenie to musze to dopracować na tyle żeby nie powodowało błędów.

Cytat(ctom @ 11.12.2013, 19:14:07 ) *
może tak.... to jakbyś kupił dziewczynie wibrator i kazała jej używać go tylko w prezerwatywie - można, tylko po co :-)

Fajnie porównanie tongue.gif
ctom
bez uraz za to porównanie ale ...
Mayka
Cytat(ctom @ 11.12.2013, 22:44:54 ) *
bez uraz za to porównanie ale ...


To w takim razie mozesz mi powiedzieć czy to co wymysliłem bedzie słuszną drogą ?
ctom
Cytat(Mayka @ 12.12.2013, 03:53:15 ) *
To w takim razie mozesz mi powiedzieć czy to co wymysliłem bedzie słuszną drogą ?


działać pewnie będzie, ale czy to "słuszna droga" śmiem wątpić - ja chcesz to podeślij na PW kod spojrzę i mogę coś powiedzieć , bo wciąż nie wiem po co wymyślasz ponownie koło. Przecież już ktoś je wymyślił, zbudował i przetestował - spójrz tu może coś dla siebie wybierzesz
Mayka
Chodzi mi o to czy jest jakaś róznica czy zainicjuje baze przez oop i bede kożystał z klasy czy w indeksie zainicjuje baze i bede z niej korzystał ?
Turson
Co masz na myśli mówiąc, że zainicjujesz bazę przez oop?
W poście #19 napisałem jak najlepiej korzystać.
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.