Cachowanie wyników zapytania przyda się zawsze tam, gdzie dane nie zmieniają się zbyt szybko. Statyczny wynik przechowywany w plikowym cache będzie również pobierany przez aplikację szybciej niż wykonanie ponownie zapytania na bazie. Jest to też prawdziwe dla wywołań metod w WebService. Problem jaki się pojawia, to jak rozsądnie cachować te wyniki?
Wróćmy na chwilę do SQL. Prędzej czy później zapytanie SQL to prosty tekst. Z tego tekstu zawsze łatwo można uzyskać skrót, który potem służy do identyfikacji pliku z cache wyniku. Takie rozwiązanie całkiem nieźle się sprawdza. Nie ma znaczenia co wrzucamy do Zend_Cache, bo zawsze podlega serializacji. Problemem jest tylko wyznaczenie unikalnej nazwy dobrze identyfikującej zapytanie i używanie tego w sposób globalny. Dlatego też osobiście używam takiego kodu:
queryCache($query, $bind, $lifetime) { $zend_cache = static::initCache($lifetime); $name = 'query_' . md5($query . serialize($bind)); $wynik = $zend_cache->load($name); if($wynik === false) { if (empty($bind)) { $wynik = self::getDb()->query($query)->fetchAll(); } else { $wynik = self::getDb()->query($query, $bind)->fetchAll(); } $zend_cache->save($wynik, $name); } return $wynik; }
Jak widać nazwa wyznaczana jest z zapytania i tablicy parametrów. To samo zapytanie, z tymi samymi parametrami daje taką samą nazwę w cache. Jak więc łatwo i uniwersalnie budować statyki w cache dla wywołania metod klasy klienta WS?
Poniżej prezentuję swoje rozwiązanie:
public static function queryCallable($callable, $parameters = array(), $lifetime = 86400, ) { $zend_cache = static::initCache($lifetime); $name = 'call_' . md5(serialize($callable) . serialize($parameters)); $wynik = $zend_cache->load($name); if($wynik === false) { $wynik = call_user_func_array($callable, $parameters); $zend_cache->save($wynik, $name); } return $wynik; }
W tym przypadku nazwa jest generowana na podstawie callable i tablicy parametrów. Klient WS realizuje wzorzec Singleton, dzięki czemu z łatwością można cachować każde wywołanie tej samej metody dla tych samych parametrów w całej aplikacji i co ważne można to zrobić w sposób stosunkowo przezroczysty. Oczywiście zamiast napisać:
$client = WSClient::getInstance(); $data = $client->callMethod($param);
Trzeba napisać:
$data = CacheFactory::queryCallable(array(WSClient::getInstance(), 'callMethod'), array($param));Uzyskany wynik będzie identyczny. Jedyny problem jest taki, że budując callable nie możemy oprzeć się na pomocy IDE. Utrudnione jest też wyszukiwanie wszystkich odwołań do metody w callable co nieco utrudnia refaktoryzację.
Brak komentarzy:
Prześlij komentarz