Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] singleton a trzy bazy danych
Forum PHP.pl > Forum > Przedszkole
patryczakowy
Witam mam mały problem mam skrypt który korzysta z trzech baz danych założenie było takie żeby podczas wykonywania skryptu były maksymalnie trzy połączenia z bazą dlatego chciałem zimplementować wzorzec singleton dl a każdej z baz jednak problem jest taki że podczas wywołania klasy z połączeniem do drugiej bazy połączenie z pierwszą zostaje przerwane po niżej przykładowy kody
  1. class db_portal extends db{
  2.  
  3.  
  4. private function __construct() {
  5. $cfg['db']['host']='localhost';
  6. $cfg['db']['user']='xxxxxx';
  7. $cfg['db']['password']='xxxxx';
  8. $cfg['db']['name']='xxxxxx';
  9. $this->conn_id = mysql_connect($cfg['db']['host'],$cfg['db']['user'],$cfg['db']['password']);
  10. mysql_select_db($cfg['db']['name'],$this->conn_id);
  11. mysql_query("SET CHARACTER SET utf8");
  12. mysql_query("SET collation_connection = utf8_unicode_ci");
  13. if(! is_resource($this->conn_id)) {
  14. return false;
  15. }
  16. }
  17. static public function connect_db () {
  18. static $objDB;
  19. if(!isset($objDB))
  20. $objDB = new db_portal;
  21.  
  22. return $objDB;
  23. }
  24. }
  25. class db_portal2 extends db{
  26.  
  27.  
  28. private function __construct() {
  29. $cfg['db']['host']='localhost';
  30. $cfg['db']['user']='xxxxxx';
  31. $cfg['db']['password']='xxxxx';
  32. $cfg['db']['name']='xxxxxx';
  33. $this->conn_id = mysql_connect($cfg['db']['host'],$cfg['db']['user'],$cfg['db']['password']);
  34. mysql_select_db($cfg['db']['name'],$this->conn_id);
  35. mysql_query("SET CHARACTER SET utf8");
  36. mysql_query("SET collation_connection = utf8_unicode_ci");
  37. if(! is_resource($this->conn_id)) {
  38. return false;
  39. }
  40. }
  41. static public function connect_db () {
  42. static $objDB;
  43. if(!isset($objDB))
  44. $objDB = new db_portal2;
  45.  
  46. return $objDB;
  47. }
  48. }
  49. $DB=db_portal::connect_db();
  50. //zapytania z bazy 1
  51. $DB2=db_portal2::connect_db();
  52. // zapytania z bazy 2
  53. $DB->query($SQL);
  54. //problem objekt $DB istnieje ale niema już połączenia z bazą przez co zapytanie się nie wykonuje
  55. //nie pomaga nawet dodanie linii wcześniej $DB=db_portal::connect_db();

Klasa db to standardowa klasa mająca metody typu query fetch itp

Ma ktoś pomysł jak można to rozwiązaćquestionmark.gif?

Z góry dzięki za sugestie.
Smertius
Wg mnie powinieneś łączenie z bazą danych przenieść do konstruktora bazy DB, a w klasach które po niej dziedziczą wywoływać konstruktor rodzica przez parent::__construct(), nie ma sensu tego pchać do każdej klasy w dodatku jeśli będziesz chciał zmienić dane do BD to bedziesz to zmieniał w N klasach? Trochę to niewygodne.

Co do Singeltona, to błędnie go implementujesz. Rzuć okiem na kod:

  1. class klasa {
  2.  
  3. private static $instance;
  4.  
  5. public function __construct() {
  6. if (!(self::$instance instanceof klasa)) {
  7. self::$instance = $this;
  8. return self::$instance;
  9. } else {
  10. return self::$instance;
  11. }
  12. }
  13. }


Tak jak powyżej, jeśli po pierwszym utworzeniu obiektu "klasa", spróbujesz go utworzyć jeszcze raz (new Klasa) to zostanie zwrócony już istniejąca instancja "klasa"

IMHO mamy PDO, mamy ORM a ludzie dalej korzystają z niewygodych, przestarzałych funkcji typu mysql_query itp. ...
Mephistofeles
Użyj np. Doctrine DBAL (czy nawet całego ORMa), załatwi sprawę kilku połączeń. Albo po prostu PDO. Mysql_ było dobre może 5 lat temu, nie pamiętam kiedy wszedł PHP 5 z PDO.
Crozin
@Smertius: Proponuje Ci sprawdzać swój kod przed podaniem, bo kompletne bzdury wypisujesz...
Smertius
Tzn?
patryczakowy
Cytat(Smertius @ 22.01.2011, 10:00:59 ) *
(..) nie ma sensu tego pchać do każdej klasy w dodatku jeśli będziesz chciał zmienić dane do BD to bedziesz to zmieniał w N klasach? Trochę to niewygodne.

Tak w N klasach bo mam N baz danych smile.gif
Cytat(Smertius @ 22.01.2011, 10:00:59 ) *
Co do Singeltona, to błędnie go implementujesz. Rzuć okiem na kod:

Co do implementacji wzorca singleton to zaczerpnełem go z tej książki
Cytat(Smertius @ 22.01.2011, 10:00:59 ) *
Tak jak powyżej, jeśli po pierwszym utworzeniu obiektu "klasa", spróbujesz go utworzyć jeszcze raz (new Klasa) to zostanie zwrócony już istniejąca instancja "klasa"

IMHO mamy PDO, mamy ORM a ludzie dalej korzystają z niewygodych, przestarzałych funkcji typu mysql_query itp. ...


i tak samo działa moja klasa objekt jest ale nie mam już połączenia z bazą danych gdyż wcześniej zainicjowałem połączenie z drugą bazą danych
Cytat
Użyj np. Doctrine DBAL (czy nawet całego ORMa), załatwi sprawę kilku połączeń. Albo po prostu PDO. Mysql_ było dobre może 5 lat temu, nie pamiętam kiedy wszedł PHP 5 z PDO.

Wygodne nie wygodne jak się ma masę kodu do przerobienia to się kombinuje tak żeby wszystkiego nie trzeba było pisać od początku, a było w miarę optymalne jeśli zainicjuje trzy połączenia do trzech różnych baz danych przy pomocy PDO to te trzy połączenia będą istnieć cały czas równolegle questionmark.gif? i co w takim razie ze wszystkimi zwykłymi zapytaniami mysql_query które już istnieją bo w obecnym momencie do póki nie inicjowałem drugiej klasy to po wywołaniu
  1. $DB=db_portal::connect_db();

jeśli w kodzie gdzieś dalej istniało coś takiego
  1. $a= mysql_query("SELECT * FROM TABELA");
  2.  


to wszystko działało bez konieczności ingerencji w już napisany kod
Fifi209
A do manuala nie łaska zajrzeć?

Cytat
resource mysql_connect ([ string $serwer = ini_get("mysql.default_host") [, string $nazwa_użytkownika = ini_get("mysql.default_user") [, string $hasło = ini_get("mysql.default_password") [, bool $nowe_połączenie = false [, int $flagi_klienta = 0 ]]]]] )


patryczakowy
Cytat(fifi209 @ 22.01.2011, 12:47:20 ) *
A do manuala nie łaska zajrzeć?

sorki ale może nie zawsze umiem wyciągnąć z manula to co mi potrzebne, niezabardzo wiem z jakimi parametrami mam wywołać to mysql_connect aby działało tak jak ja chcę mysql_connect , nawet jeślim dam tak
  1. $this->conn_id = mysql_connect($cfg['db']['host'],$cfg['db']['user'],$cfg['db']['password'],true);

to nie działa, czemu zresztą się nie dziwię gdyż przy drugim wywołaniu objekt istnieje więc konstruktor nie jest wywoływany, z resztą takie było założenie żeby z bazą łączyć się tylko raz

chyba coś przekombinowałem powoli zaczyna dochodzić do mnie że bez przepisania wszystkiego pożądanego efektu nie osiągnę niemniej jednak czekam na jakieś koło ratunkowe
Crozin
1. mysql_query powinno mieć określone z którego połączenia korzysta (patrz drugi argument funkcji).
2. Przestań korzystać z Singletona, bo na stronach WWW jest naprawdę baaaaardzo niewiele sytuacji, gdzie jego użycie miałoby sens, a korzystanie z tego wzorca poza jedną zaletą (powodem, dla którego stworzono go - czyli zapewnieniem istnienia co najwyżej jeden instancji danej klasy) ciągnie za sobą masę problemów.
3. Zapewne korzystasz z Singletona by uzyskać globalny dostęp do bazy danych (to jest złe użycie oczywiście), ale mógłbyś wykorzystać coś takiego:
  1. // Zakładam, że klasa DB to mniej-więcej coś takiego:
  2.  
  3. class DB {
  4. protected $connection;
  5.  
  6. public function __construct($host, ...) {
  7. $this->connection = mysql_connect(...);
  8. }
  9.  
  10. public function query($sql) {
  11. $result = mysql_query($sql, $this->connection);
  12. }
  13.  
  14. // etc.
  15. }
  16.  
  17. // Tak więc utwórzmy sobie najpierw jakiegoś globalnego (złe, ale skoro tak już musisz mieć) menadżera połączeń:
  18. class DBManager {
  19. protected static $connections = array();
  20.  
  21. public static function get($name) {
  22. return self::$connections[$name];
  23. }
  24.  
  25. public static function set($name, DB $connection) {
  26. self::$connections[$name] = $connection;
  27. }
  28. }
  29.  
  30. // W którymś tam miejscu skryptu inicjalizujesz połączenia:
  31.  
  32. $defaultConnection = new DB('...', '...');
  33. $extraConnection = new DB('....');
  34. $yetAnotherConnection = new DB(...);
  35.  
  36. // I dodajesz je do menadżera:
  37.  
  38. DBManager::set('default', $defaultConnection);
  39. DBManager::set('extra', $extraConnection);
  40. DBManager::set('yetAnothert', $yetAnotherConnection);
  41.  
  42. // Teraz w dowolnej części aplikacji możesz zrobić coś w stylu:
  43.  
  44. $db = DBManager::get('extra');
  45. $db->query('...');
  46.  
  47. $db = DBManager::get('default');
  48. $db->fetchArray('....');


Cytat
Tzn?
To znaczy, że to co podałeś nie jest Singletonem. To papka bezsensownego kodu (konstruktor zwracający coś? wtf?!)
patryczakowy
To co podałeś rozwiązało prawie cały problem i wielkie dzięki, jednak tak jak pisałem wcześniej niestety wiąże się to z przepisaniem wszystkich wystąpień mysql_query, a chciałem tego uniknąć jak widać nie da rady, ale może to i lepiej przy okazji przejże wszystkie zapytania do bazy smile.gif
Crozin
Jeżeli i tak jesteś zmuszony przepisać zapytania to skorzystaj z PDO, które mimo iż nie idealne jest znacznie lepszym interfejsem niż funkcje mysql_*().
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.