2012-02-08 7 views

Odpowiedz

1

Najlepszym sposobem jest zawinięcie tworzenia instancji PDO do postaci singleton (np. MyPDOFactory), która przechowuje zarówno instancję, jak i czas utworzenia, w ten sposób można go ponownie użyć lub odtworzyć po osiągnięciu TTL (2 lub 3 sekundy to więcej niż wystarczająca ilość dla większości aplikacji). Musisz tylko wywołać MyPDOFactory :: get(), aby uzyskać poprawny PDO, którego możesz użyć do przygotowania PDOStatement, po prostu upewnij się, że wykonujesz go JAK NAJSZYBCIEJ.

+0

Rozumiem twój pomysł, ale naprawdę powinieneś dodać kod do swojej odpowiedzi. –

+0

Co się stanie, jeśli prowadzisz zestaw zapytań, które są a) transakcyjne, i b) zdarza się, że trwa dłużej niż TTL? – GordonM

-1

Myślę, że to może ci pomóc.

/* Your Database Name */ 
    $dbname = 'mydatabase'; 

    /* Your Database User Name and Passowrd */ 
    $username = 'root'; 
    $password = 'password'; 

    try { 
     /* Establish the database connection */ 
     $conn = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password); 
     $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    /* your code goes here*/ 
} catch(PDOException $e) { 
     echo 'ERROR: ' . $e->getMessage(); 
    } 
    //mysql_close($conn); 

    $conn=null; 
+0

Twoja odpowiedź jest bezużyteczna w przypadku ponownego łączenia po upływie limitu czasu. W bloku try powinieneś umieścić kod zapytania i jeśli połączenie zniknęło, podłącz ponownie blok catch. A potem jakoś uruchom ponownie zapytanie ... –

0

Ponowne połączenie z bazą danych po błędzie jest w rzeczywistości znacznie bardziej skomplikowanym problemem niż na pierwszy rzut oka.

Moim pierwszym pomysłem było napisać prosty klasy otoki dla PDO, że serwery proxy metod na wewnętrznej obiektu PDO i może obsługiwać błędy połączenia sama:

class BetterPDO extends PDO 
{ 
    private $realPDO = NULL; 
    private $dsn  = ""; 
    private $username = ""; 
    private $password = ""; 
    private $options = []; 

    public function __construct ($dsn, $username = "", $password = "", $options = []) 
    { 
     $this -> dsn = $dsn; 
     $this -> username = $username; 
     $this -> password = $password; 
     $this -> options = $options; 
    } 

    private function getRealPDO() 
    { 
     if (is_null ($this -> realPDO)) 
     { 
      $this -> realPDO = new PDO ($this -> dsn, $this -> username, $this -> password, $this -> options); 
     } 
     return $this -> realPDO; 
    } 

    // We're only implementing exec for brevity but you have to do this for all public methods of PDO 
    public function exec ($sql) 
    { 
     $retries = 0; 
     while (true) 
     { 
      try 
      { 
       return $this -> getRealPDO() -> exec ($sql); 
      } 
      catch (PDOException $ex) 
      { 
       $this -> realPDO = NULL; 
       if (++$retries > 5) 
       { 
        // We've passed our retry limit 
        throw $ex; 
       } 
      } 
     } 
    } 
} 

Ponieważ klasa ta rozciąga PDO może być stosowany wszędzie tam, gdzie można zastosować ogólną klasę PDO.

Jak widać, to podejście da ci kilka ponownych prób, zanim metoda exec() zrezygnuje, pozwalając na ponowne połączenie po przejściowych błędach (jest to tylko demonstracja i brakuje niektórych funkcji, których potrzebowałaby prawdziwa implementacja, np. powstrzymywanie pomiędzy ponownymi próbami, odpowiednim rejestrowaniem błędów itp.). Takie podejście wymagałoby również sprawdzenia specyfiki wyjątku PDO, ponieważ nie chcesz, aby błędy składni MySQL powodowały resetowanie połączenia i próbę ponowienia. Chcesz tylko, aby to się stało w takich sytuacjach, jak "Serwer zniknął".

Jak można zauważyć, wdrożenie wszystkich metod PDO prokuratorii stałoby się ciężkim zadaniem, choć trzeba to zrobić tylko wtedy, gdy prawdopodobnie warto zainwestować w ten wysiłek.

Istnieje jednak znacznie większy problem, który jest dość powszechnym problemem dla każdego kodu, który komunikuje się z bazą danych, a nie tylko z PDO. Co się stanie, jeśli połączenie zostanie utracone w trakcie transakcji? Nie chcesz, aby twój skrypt ponownie się łączył i odbierał miejsce, w którym zostało przerwane, ponieważ cała praca wykonana do ostatniego zatwierdzenia zostanie utracona i istnieje duże prawdopodobieństwo, że nie byłoby logiczne, aby wznowić po ponownym połączeniu będziesz musiał zacząć od nowa. Dlatego prawdopodobnie chciałbyś, aby cały skrypt zaczął się od nowa, a próba ponownego połączenia nie miałaby sensu. Prawdopodobnie dlatego mySQLI obsługuje ponowne łączenie, ale PDO tego nie robi.

Jeśli twój skrypt odczytuje tylko lub nietransakcyjne zapisy, to powyższe podejście ma wartość, ale jak tylko wyrzucisz transakcje do miksu, w rzeczywistości jesteś o wiele lepiej bez próby ponownego połączenia.