Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP] Klasa do "keszowania" zapytań
Forum PHP.pl > Inne > Oceny
adam882
Witam

Prosiłbym o sprawdzenie poprawności w napisaniu klasy do "keszowania" zapytań mysql (czy chociaż dobrze zacząłem ją pisać), gdyż nie mam wiedzy na temat zaawansowanego programowania w php (którego trochę mogłem już zapomnieć) i zawsze używałem gotowych klas mysql. Klasa nie jest jeszcze dopracowana.
  1. //Klasa mysql cache
  2. class mysql
  3. {
  4. //Ustawienia
  5. private $folder='temp/'; //Folder cache
  6.  
  7. //Pomocne w klasie
  8. private $connect; //Do połączenia i zamykania połączenia z mysql
  9. public $row=array(); //Do pobierania wyników z bazy
  10. private $cache_buffer=array(); //Przechowuje tutaj dane z cache
  11. public $cache_stan=0; //Pomaga w zakończeniu pętli w fetch_assoc()
  12. public $array_num=0; //Ostatni numer tablicy
  13. private $zapytanie_bez_cache; //Gdy cache jest nieaktywne przypisuje mu wyniki z mysql_query(), aby móc odtworzyć rekordy z użyciem w funkcji klasy: fetch_assoc
  14. private $cache_name; //Nazwa pliku cache
  15. public $queries=0; //Zlicza zapytania
  16.  
  17.  
  18. ########## Konstruktor ##########
  19. function __construct($host,$user,$pass,$baza)
  20. {
  21. $this->connect=@mysql_connect($host,$user,$pass) or die('Nie mogę się połączyć z mysql <br /> Błąd: '.mysql_error());
  22. @mysql_select_db($baza) or die('Nie mogę wybrać bazy <br /> Błąd: '.mysql_error());
  23.  
  24. }
  25. ##############################
  26.  
  27.  
  28.  
  29. ########## Destruktor
  30. function __destruct()
  31. {
  32. @mysql_close($this->connect);
  33. }
  34. ##############################
  35.  
  36.  
  37.  
  38. ########## Zapytanie ##########
  39. public function query($zapytanie, $cache=false) //Drugi parametr określa, czy włączyć cache i jednocześnie przypisuje nazwę pliku
  40. {
  41.  
  42. $this->cache_name=$cache; //Daje znać, czy użyć cache jednocześnie tworząc nazwę pliku
  43.  
  44. if($this->cache_name) //Z cachowaniem (czy nazwa pliku cache została podana)
  45. {
  46.  
  47. if(file_exists(''.$this->folder.''.$this->cache_name.'.plik')) //Gdy plik cache istnieje
  48. {
  49. $this->cache_buffer=unserialize(file_get_contents(''.$this->folder.''.$this->cache_name.'.plik')); //Wczytuje tablice z pliku
  50. $this->array_num=count($this->cache_buffer); //Liczba elementów tablicy
  51. }
  52. else //Gdy nie ma pliku cache, to tworzymy go
  53. {
  54. $temp=array();
  55. $wynik=mysql_query($zapytanie) or die('Problem z zapytaniem <br /> Błąd: '.mysql_error()); //Zapytanie do bazy
  56. $this->queries++; //Liczba zapytań rośnie
  57.  
  58. while($r=mysql_fetch_assoc($wynik))
  59. {
  60. $temp[]= $r;
  61. }
  62. ignore_user_abort(1); //Gdzieś spotkałem się z takim zaleceniem
  63. $this->cache_buffer=$temp; //Przenosi tablicę z wynikami do buffera
  64. $this->array_num=count($this->cache_buffer); //Liczba elementów tablicy
  65. @file_put_contents(''.$this->folder.''.$this->cache_name.'.plik',serialize($temp)); //umieszczenie pliku
  66. }
  67. return 1;
  68. }
  69. else //Bez cachowania
  70. {
  71. $this->zapytanie_bez_cache=mysql_query($zapytanie) or
  72. die('Problem z zapytaniem<br /> Błąd: '.mysql_error()); //Zapytanie do bazy, przypisuje je zmiennej, aby móc potem pobrać rekordy
  73. $this->queries++; //Liczba zapytań rośnie
  74. }
  75.  
  76. }
  77. ##############################
  78.  
  79.  
  80.  
  81. ########## Pobieranie wyników ##########
  82. public function fetch_assoc()
  83. {
  84. if($this->cache_name) //Z cachowaniem
  85. {
  86.  
  87. if($this->array_num==$this->cache_stan){ //Czy ilość elementów jest równa numerowi tablicy, jeśli nie, to numer tablicy się zwiększa
  88. return 0; //Pobrano wszystkie elementy tablicy - koniec pętli
  89. }
  90. else
  91. {
  92. $this->row = $this->cache_buffer[$this->cache_stan]; //Tworzy tablicę do wyświetlania wyników, począwszy od tablicy z numerem 0
  93. $this->cache_stan++; return 1; //Pobiera elementy, indeks zwiększa się, pętla trwa
  94. }
  95. }
  96. else //Bez cachowania
  97. {
  98. $this->row = mysql_fetch_assoc($this->zapytanie_bez_cache);
  99. return $this->row;
  100. }
  101. }
  102. ########################################
  103.  
  104.  
  105.  
  106. ########## Mysql_num_rows ##########
  107. public function num_rows()
  108. {
  109. if($this->cache_name) //Z cachowaniem
  110. {
  111. return $this->array_num;
  112. }
  113. else //Bez cachowania
  114. {
  115. return mysql_num_rows($this->zapytanie_bez_cache);
  116. }
  117. }
  118. ####################################
  119.  
  120.  
  121. }
  122.  
  123. ##################################################
  124. ###################### TEST ######################
  125. ##BENCHMARK
  126. function czas()
  127. {
  128. $time = explode(" ", microtime());
  129. $a= (double)$time[0];
  130. $b= (double)$time[1];
  131. return $b + $a;
  132. }
  133. ##BENCHMARK
  134.  
  135. $poczatek = czas();
  136. $x=0;
  137.  
  138. $sql=new mysql('localhost','root','krasnal','baza');
  139. $sql->query('SELECT nazwa FROM rekordy ORDER BY id DESC LIMIT 100','NazwaPlikuCache'); //Drugi parametr tworzy plik cache o takiej nazwie, nie podając go cache się wyłącza
  140. if($sql->num_rows()>0){echo 'Są rekordy ('.$sql->num_rows().')<br />';}else{echo 'brak rekordów!<br />';} //Test mysql_num_rows
  141. while($sql->fetch_assoc())
  142. {
  143. $x++;
  144. echo $x.') '.$sql->row['nazwa'].'<br />';
  145.  
  146. }
  147. $koniec= czas();
  148. $c = $koniec - $poczatek;
  149. echo "<br /><br />czas generowania " . substr($c, 0, 5) . " sek.<br />Zapytań: ".$sql->queries;
  150. ##################################################
  151. ###################### TEST ######################
erix
  • baty za małpy przed funkcjami. Kopiesz sobie grobowiec. Coś pójdzie nie tak, to się tylko naszukasz.
  • dlaczego nie PDO/MySQLi?
cepa
no troche do poprawienia jest:

1) nie tworz polaczenia w klasie tylko przekazuj polaczenei do klasy

2) tranzakcje i locki

3) nie uzywaj plikow do cachowania bo ci sie to wysypie, w php nie ma mutexow na pliki wiec istnieje prawdopodobienstwo ze kilka procesow php zacznie pisac w tym samym czasie do jednego pliku i uszkodzi cache

4) uzyj persistent storage, np: apc smile.gif
adam882
@erix
"małpy" usunę, sam nie wiem po co je dałem na czas testowania i pisania klasy. Wolę pozostać przy samym MySQL (przyzwyczajenie).

@cepa
W wielu klasach mysql, które przeglądałem to mniej więcej tak jak u mnie tworzono połączenia wewnątrz klasy.
Stosowanie plików cache jest złym rozwiązaniem? Możliwe, że plik cache może się uszkodzić, ale pewnie da się to jakoś zabezpieczyć, żeby nie dochodziło do nadpisywania pliku w tym samym czasie (zresztą żeby tak się stało, to chyba musiałbym mieć serwis, na którym przesiaduje z kilka tys osób online). Wiele serwisów używa cache mysql na plikach. Nie potrzebna jest mi mega zaawansowana klasa, wystarczy mi tylko, żeby była szybka, prosta, stabilna i używała cache smile.gif
cepa
Cytat(adam882 @ 24.06.2011, 15:08:08 ) *
W wielu klasach mysql, które przeglądałem to mniej więcej tak jak u mnie tworzono połączenia wewnątrz klasy.

to ze w wielu to widziales to nie znaczy ze bylo to dobre, powiedzonko o muchach i gownie jest chyba najbardziej adekwatne smile.gif

Cytat(adam882 @ 24.06.2011, 15:08:08 ) *
Stosowanie plików cache jest złym rozwiązaniem? Możliwe, że plik cache może się uszkodzić, ale pewnie da się to jakoś zabezpieczyć, żeby nie dochodziło do nadpisywania pliku w tym samym czasie (zresztą żeby tak się stało, to chyba musiałbym mieć serwis, na którym przesiaduje z kilka tys osób online). Wiele serwisów używa cache mysql na plikach. Nie potrzebna jest mi mega zaawansowana klasa, wystarczy mi tylko, żeby była szybka, prosta, stabilna i używała cache smile.gif

cache na plikach nie jest zlym rozwiazaniem jak twoja aplikacja radzi sobie z konkurencyjnoscia, przykladowo taka baza danych tez operuje na plikach ale zapis do plikow jest zabezpieczony aby nie bylo sytuacji ze nagle dane z dwoch polaczen zaczna sie nawzajem nadpisywac.
php jest wolne i nawet przy niewielkim ruchu bedziesz mial przeklamania, sproboj uzyc swojego cache jako np: licznik odwiedzin.
poprostu takie rozwiazanie w php nie jest stabilne, apc czy memcache sa o niebo lepsze i szybsze smile.gif
adam882
Czyli w takim razie postaram się zmodyfikować klasę tak, aby połączenie było przekazywane do niej, tylko czy wtedy jest sens użycia mysql_close() w __destruct?
Zna ktoś może jakieś proste sposoby na zabezpieczenie nadpisywania plików w klasie w przypadku kilku połączeń?
cepa
Cytat(adam882 @ 24.06.2011, 15:49:34 ) *
Czyli w takim razie postaram się zmodyfikować klasę tak, aby połączenie było przekazywane do niej, tylko czy wtedy jest sens użycia mysql_close() w __destruct?

nie ma sensu, jak ktos wyzej zauwazyl uzycie PDO byloby wygodniejsze, w destruktorze zwolnilbym referencje do obiektu bo to jest skurwoza podczas testowania pozniej, czyli poprostu $this->_connection = null

Cytat(adam882 @ 24.06.2011, 15:49:34 ) *
Zna ktoś może jakieś proste sposoby na zabezpieczenie nadpisywania plików w klasie w przypadku kilku połączeń?

nie ma, najprostsze to wlasnie apc, memcache itp itd, poszperaj na necie troche o thread race smile.gif
erix
Cytat
Wolę pozostać przy samym MySQL (przyzwyczajenie).

Radzę poczytać o tym, czy jest sens stosować to przyzwyczajenie...
Fifi209
Cytat(cepa @ 24.06.2011, 14:33:01 ) *
1) nie tworz polaczenia w klasie tylko przekazuj polaczenei do klasy

Dlaczego?
Cytat(cepa @ 24.06.2011, 14:33:01 ) *
2) tranzakcje i locki

Transakcje jak już
cepa
Cytat(Fifi209 @ 24.06.2011, 16:10:43 ) *
Dlaczego?


1) mozna wtedy uzywac obiektu w sytuacji jak potrzebne jest wiecej niz jedna baza, chociazby skrypty migracji itp
2) testowanie, jezeli masz interfejs obiektu poalczenia to mozna zrobic mocka, lub podawac mu inne zrodla danych a kod nadal dziala jak nalezy

thek
Nikt nie powiedział, że klasa połączenia to Singleton? wink.gif Jeśli nie jest to można się bawić z nieograniczona liczbą obiektów i tym samym baz.
Fifi209
Cytat(thek @ 24.06.2011, 17:57:39 ) *
Nikt nie powiedział, że klasa połączenia to Singleton? wink.gif

Nie, bo nie jest.
Cytat(thek @ 24.06.2011, 17:57:39 ) *
Jeśli nie jest to można się bawić z nieograniczona liczbą obiektów i tym samym baz.

I dobrze, bo nie chciałbym być zmuszony do korzystania z tylko jednego połączenia czy bazy.
adam882
Zastanawiam się nad wdrożeniem APC, jednak prawie nic nie słyszałem o tym module (opieram się jedynie teraz na manualu php). Z tego co mi się wydaje dane będą przechowywane gdzieś w pamięci, więc folder cache nie będzie potrzebny?
Czy działanie takiej klasy powinno wyglądać mniej więcej tak?: Sprawdź czy istnieje cache przez apc_exists(), jeżeli tak, to pobiera je przez apc_fetch(), jeżeli nie to tworzy przy pomocy apc_store(). Całe cache kasowane będzie przy pomocy apc_clear_cache(), a elementy przy apc_delete()? Czy używając apc w cache mysql powinno się określać czas żywotności takiego cache?
cepa
http://files.ognisco.com/kickasscache/kickasscache-20110608

tutaj jest prosta klaska ktora realizuje cache z apc i jest zabezpieczona przed thread race
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.