2012-11-02 17 views
6

przykładowa aplikacja, posiadająca informacje o pracownikach i dostępna dla różnych aplikacji, takich jak lista płac i poz. Mam dane pracowników w jednej bazie danych, dane płac i pos w oddzielnych bazach danych.Singleton z wieloma bazami danych

Mam klasę połączenia z bazą danych, jak poniżej, więc za każdym razem chcę uzyskać połączenie z bazą db i po prostu zrobić $conn = Database::getInstance(db1).

działa świetnie, ale w zasadzie działa bardzo wolno. sprawia, że ​​aplikacja działa bardzo wolno. Jakieś wskazówki, dlaczego tak jest, a może lepiej, ale alternatywne pomysły, aby to zrobić?

Każda pomoc będzie mile widziana

<?php  
class Database { 
     private $db; 
     static $db_type; 
     static $_instance; 

     private function __construct($db){ 
      switch($db) { 
       case "db1": 
        try{ 
         $this->db = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD); 
        } 
        catch(PDOException $e){ 
         print "Error!: " . $e->getMessage() . "<br />"; 
         die(); 
        } 
       break; 
       case "db2": 
        try{ 
         $this->db = new PDO("mysql:host=" . DB_HOST_2 . ";dbname=" . DB_NAME_2, DB_USER_2, DB_PASSWORD_2); 
        } 
        catch(PDOException $e){ 
         print "Error!: " . $e->getMessage() . "<br />"; 
         die(); 
        } 
       break; 
      } 
      self::$db_type = $db; 

     } 

     private function __clone(){} 

     static function getInstance($db_type){ 
      if(!(self::$_instance) || $db != self::$db_type){ 
       self::$_instance = new self($db_type); 
      } 
      return self::$_instance; 
     } 
    } 
?> 
+1

Nawiązanie połączenia z bazą danych nie powinno zająć dużo czasu i nie sądzę, że twoja aplikacja będzie "wolna" ogólnie, ponieważ masz różne bazy danych do połączenia z . Czy bazy danych są lokalne? lub na zdalnym serwerze? – Dan

+0

bazy danych są lokalne. Obecnie używam tego podejścia i jego ładowanie zajmuje dużo czasu, w porównaniu z tym, kiedy mam wszystko w jednym db –

+0

Możesz pomóc znaleźć konkretną linię spowalniając rzeczy przez przechwytywanie microtime() przed po pewnych liniach. Jeśli to pomoże, możesz w konkretny sposób oddzielić swój problem od linii łączącej się z bazą danych. – Dan

Odpowiedz

1

Dzięki temu projektowi. Jeśli zmienisz bazy danych, to niszczy połączenie z poprzednią bazą danych.

Utwórz osobne obiekty dla każdego połączenia, a następnie przełącz między obiektami połączenia.

Nie jest to również bezpieczne z tego samego powodu. Jeśli wiele funkcji uderza w tym samym czasie, można odłączyć inne przed zakończeniem ładowania.

Naprawdę powinieneś po prostu utworzyć nowy obiekt połączenia dla każdej funkcji i nie udostępniać jej między funkcjami lub innymi obiektami.

+0

Awesome! Zmieniono go na tablicę zawierającą obiekty, działa perfekcyjnie! –

+2

dla innych odsyłających: 'statycznej funkcji getInstance ($ db_type = "") { \t \t \t \t if (isset (self :: $ połączeń [$ db_type]!)) { \t \t \t self :: $ połączeń [ $ db_type] = new self ($ db); \t \t} \t \t return self :: $ connections [$ db_type]; \t} ' –

+0

@ user1239663 Jaki był twój ukończony nowy kod? – johnny

0

Jak o zmianę jej również używać leniwy obciążenia. Nie musisz łączyć się z bazami danych u wykonawcy. Łącz się tylko wtedy, gdy baza danych jest wymagana po raz pierwszy. W ten sposób, jeśli strona używa tylko jednego z połączeń, nie musi czekać na inne bazy danych.

+0

Niestety nie wiesz co masz na myśli, czy mógłbyś wytłumaczyć nieco więcej? –

1

Nie twórz nowego obiektu w sposób ciągły. To, co się dzieje, to to, że za każdym razem, gdy żądasz innego typu bazy danych, odtwarzasz go za pomocą nowego słowa kluczowego (chociaż trudno to potwierdzić, nie widząc kodu, który używa tego).

$ instancją jest statyczny element, więc ciągle go zastępujesz, gdy zmieniasz typ bazy danych. tak to $ db_type dla tej sprawy

Chociaż jest to przesadą, co robisz (dlaczego nie po prostu mieć dwie zmienne dla każdego DB?), można spróbować czegoś więcej tak:

<?php  
class Database { 
     private $db; 
     static $db_types; 


     private function __construct($db){ 
      switch($db) { 
       case "db1": 
        try{ 
         $db_types[$db] = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD); 
        } 
        catch(PDOException $e){ 
         print "Error!: " . $e->getMessage() . "<br />"; 
         die(); 
        } 
       break; 
       case "db2": 
        try{ 
         $db_types[$db] = new PDO("mysql:host=" . DB_HOST_2 . ";dbname=" . DB_NAME_2, DB_USER_2, DB_PASSWORD_2); 
        } 
        catch(PDOException $e){ 
         print "Error!: " . $e->getMessage() . "<br />"; 
         die(); 
        } 
       break; 
      } 


     } 

     private function __clone(){} 

     static function getInstance($db_type){ 
      if(!inarray($db_types[$db_type]){ 
       $db_types[$db_type] = new self($db_type); 
      } 
      return $db_types[$db_type]; 
     } 
    } 
?> 

UWAGA: składnia jest prawdopodobnie wyłączona. Chciałem tylko zademonstrować wzór.

+0

Pozwól mi to wypróbować i dam ci znać. –

+0

udało się to uruchomić, ale nie posortowano problemu z szybkością. nadal ładuje się dość długo. myślę, że być może coś innego jest przyczyną tego problemu, ale spróbuję rozwiązania przez prodigitalson porównać, wtedy będę wiedzieć –

0

Sprawdź wartość DB_HOST i DB_HOST_2. Wcześniej odkryłem, że MySQL bardzo wolno łączy się przy użyciu "127.0.0.1", ale łączy się natychmiast używając "localhost".

Wszystko zależy od konfiguracji serwera, ale może pomóc.

1

Nie rozumiem, dlaczego spowodowałoby to spowolnienie innych niż fakt, że ciągle zmieniasz połączenia. Jedyne co może sugerować tutaj jest umożliwienie wielu połączeń zamiast nich przełączania:

class Database { 
    protected static $connections; 

    protected $activeConnections = array(); 

    protected static $instance; 

    protected function __construct() { 

    } 

    public static loadConnections(array $connections) { 

     self::$connections = $connections; 
    } 

    public function getConnection($name) 
    { 
     if(!isset($this->activeConnections[$name]) { 
      if(!isset(self::$connections[$name]) { 
      throw new Exception('Connection "' . $name . '" is not configured.'); 
      } 

      $this->activeConnections[$name] = new PDO(
       self::$connections[$name]['dsn'], 
       self::$connections[$name]['username'], 
       self::$connections[$name]['password'] 
     ); 

     } 

     return $this->activeConnections[$name]; 
    } 
} 

// usage 

Database::loadConnections(array(
    'db1' => array(
     'dsn' => "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, 
     'user' => DB_USER, 
     'password' => DB_PASSWORD, 
    ), 
    'db2' => array(
     'dsn' => "mysql:host=" . DB_HOST2 . ";dbname=" . DB_NAME2, 
     'user' => DB_USER2, 
     'password' => DB_PASSWORD2, 
))); 

$conn1 = Database::getInstance()->getConnection('db1'); 
$conn2 = Database::getInstance()->getConnection('db2'); 

Korzystanie coś takiego rzeczywiście można manange kilka otwartych połączeń na raz, a oni są leniwi załadowany - co oznacza, że ​​nie faktycznie instancję połączenie PDO, dopóki nie poprosisz o to z numerem Database::getConnection. Podobnie możesz wprowadzić dodatkowe DSN i poświadczenia w dowolnym momencie. Osobiście wczytałem konfigurację formularzy bezpośrednio do klasy zamiast twardego kodowania ich stałymi klasami.wtedy możesz tak coś takiego:

// gives us an array 
$config = Config::load('path/to/db/config.yml'); 

Database::loadConnections($config); 
+0

pozwól mi to wypróbować i dam znać, jak to idzie –

+0

przepraszam, czy brakuje tej statycznej funkcji getInstance()? –

+0

To nie jest pełna klasa ... właśnie przedstawiłem różnice z twoimi :-) – prodigitalson

Powiązane problemy