Home > ORM, PHP, PostgreSQL, Zend Framework > Zend Framework i keszowanie zapytań do bazy danych

Zend Framework i keszowanie zapytań do bazy danych

Witam, Od pewnego czasu programiści PHP naśladują programistów Javy, sam zresztą to robię. Efektem tego jest przenoszenie wzorców projektowych z Javy do PHP. Na przykład Zend Framework a w szczególności jego kod odpowiedzialny za bazy danych – Zend_Db (działający prawie jak ORM) przypomina w pewien sposób to, za co świat Javy pokochał Hibernate. Konsekwencją użycia ORM w projekcie jest to, że spada nam złożoność zapytań do bazy danych, natomiast zwiększa się ich ilość. Hibernate potrafi keszować obiekty. Zend Framework niestety nie. Jednak wczoraj tego bardzo potrzebowałem, renderowanie prostej strony WWW wymagało 500 zapytań do bazy, grrr, z czego 450 było powtórzeniem poprzednich zapytań. O ile keszowanie obiektów było by bardzo skomplikowane, to w miarę prosto można było keszować wyniki zapytań SQL w obrębie jednego żądania HTTP. Jak się do tego zabrać? Zauważyłem, że wszystkie zapytania do bazy danych produkowane przez Zend Framework w pewnym momencie trafią do metody query obiektu Zend_Db_Adapter_*, fajnie:). Naszą klasę keszującą trzeba odziedziczyć po tej klasie. Oczywiście można to zrobić na wiele innych sposobów, i bardzo ładnie wpasować w to wzorzec projektowy dekorator, ale ja nie miałem czasu. Modyfikujemy metodę query, tak by zapamiętywała swoje wyniki i trzymała w keszu. U mnie działa coś takiego (wstydził bym się tego kodu, gdyby nie to że robi coś na prawdę przydatnego):
class JakubiakDbAdapterPdoPgsql extends Zend_Db_Adapter_Pdo_Pgsql{
  public function query($sql, $bind = array()){
    $sql = $sql . ""; // a sprobuj no bez tego
    $hash = $this->_calculateHash($sql,$bind);
    // czy uda nam sie pobrac z kesza
    if($this->_isCacheEnabled) {
      if($this->_allowCache($sql,$bind)) {
        if(isset($this->_cachedResults[$hash])) {
          return $this->_cachedResults[$hash];  
        } 
      }
    }
    $res = parent::query($sql, $bind);
    // dopisanie do kesza
    if($this->_isCacheEnabled) {
      $this->_cachedResults[$hash] = $res;
    }
    return $res;
  }
  // pozwalam na keszowanie tylko zapytan rozpoczynajacych sie od select
  private function _allowCache($sql,$bind) {
    return preg_match("/^select/i",$sql));
  }
  private function _calculateHash($sql,$bind) {
    return md5($sql.var_export($bind,true));
  }
  [...]
}
Ten kod omal nie zadziała. Jednak trzeba zrobić jeszcze parę myków. Przeciążyć konstruktor naszego adaptera.
  public function __construct($config) {
    parent::__construct($config);
    $this->getConnection()->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('JakubiakDbStatement', array($this)));
  }
I dopisać taką oto koszmarną klasę:
class JakubiakDbStatement extends PDOStatement {
  $_cache = null;
  public function fetchAll($how, $class_name=null, $ctor_args=null) {
    if(!empty($this->_cache)) {
      return $this->_cache;
    }
    $this->_cache = parent::fetchAll($how);
    return $this->_cache;
  }
}
Ten kod, ma prawo nie działać i zawiera błędy. Jednak u mnie działa. I to dobrze działa. Zamiast 500 zapytań do bazy mam ich 50. Serwer jest mi za to wdzięczny, nie trzeba już oliwić wentylatorka od chłodzenia;). PS. do testów użyłem starej wersji Zend_Framework – 0.9.1.
Categories: ORM, PHP, PostgreSQL, Zend Framework Tags:
  1. Martio
    August 4th, 2007 at 10:45 | #1

    Czemu PHP idzie w kierunku Javy? Skoro Java jest taka dobra (bo jest) i ma zajebiste rozwiązania (bo ma), to na cholerę przenosić je na PHP ,skoro można przenieść się na Javę?

  2. Antoni Jakubiak
    August 5th, 2007 at 21:46 | #2

    W moim przypadku decyzja o wyborze PHP do tego projektu była prosta. Miałem bardzo mało czasu i PHP znam lepieł.

    To co robię teraz to jest właśnie przesiadka na Jave. Jednak, jest to duże wyzwanie.
    Gdy piszę coś dla siebie to ryzukuje tylko swój czas.
    Gdy pracuję w zespole programistów w firmie Support to ryzyko mojego błędu bierze na siebie mój szef – którego poinformowałem w CV uczciwie o tym, że technologii JEE dopiero się uczę.
    Jednak, gdy pracuję dla klienta – to muszę wybrać technologie najlepszą dla niego. W tym wypadku było to PHP.

    Jednak to technologia JEE jest wspaniała i to jest właśnie przyszłość.

  3. August 8th, 2011 at 10:44 | #3

    Rzeczywiście koszmarny kawałek kodu – bardzo dobry przykład “code bloat” ;) Po co te nowe klasy, dziedziczenia, skoro można dopisać te kilka linijek bezpośrednio w funkcji query Zend_Db_Adapter_? Nie rozumiem też tego zwyczaju haszowania co popadnie – nigdy bym nie zahashował zapytania SQL, choćby dlatego że może dojść do kolizji (2 różne zapytania – ten sam md5).

  1. No trackbacks yet.

Subscribe without commenting