Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP]Cachowanie danych.
Forum PHP.pl > Forum > Przedszkole
Gruchol
Witam,
Po dłuższym czasie postanowiłem wrócić do przygody z php. Jako swój pierwszy projekt postanowiłem zakodować stronę pewnej gry.
Aktualnie robię ranking, jednak przeszukiwanie całej bazy w której są dane kilkudziesięciu tysięcy użytkowników za bardzo obciąży serwer.
Potrzebuje wyświetlić i cachować takie dane jak czas gry, poziom gracza jakieś tam osiągnięcia itd. Chciałbym aby te dane aktualizowały się np. co 10 minut.
Na internecie znalazłem klasę nospora, jednak nie wiem jeszcze jak za bardzo się jej używa.
Prosiłbym Was o jakieś wskazówki i poradniki (mogą być anglojęzyczne) jakiej klasy użyć ew. jak to rozwiązać.
Pozdrawiam.
Rysh
Zazwyczaj klasy tego typu działają na podobnej zasadzie.
Czyli klasa sprawdza czy zapytanie jest cachowane jeśli jest to je pobiera i wyświetlasz, w przeciwnym wypadku pobierasz dane z bazy danych i wysyłasz do cache na określona ilość sekund.
Biblioteka sama sprawdzi czy czas świeżości danych został przekroczony, jeśli został to nic nie zwróci.
Jeśli masz problem najlepiej z wpadnij konkretnym bilbioteką/kodem, będzie łatwiej nam pomóc.

Takich bibliotek znajdziesz wiele:
https://www.google.pl/search?q=php+cache+github
Gruchol
Napisałem taką funkcję

  1. function DisplayRanking()
  2. {
  3. global $db;
  4.  
  5. $info = $db->query("SELECT player.player.id, player.player.name, player.player.level, player.player.playtime, player.player.last_play, player.guild.name AS 'guild_name' FROM player.player, player.guild, player.guild_member WHERE player.player.id = player.guild_member.pid AND player.guild.id = player.guild_member.guild_id ORDER BY level DESC LIMIT 5");
  6. $info->execute();
  7.  
  8. echo "<table style='border: 1px solid;'>";
  9.  
  10. while($row = $info->fetch(PDO::FETCH_ASSOC))
  11. {
  12. if(!empty($row['guild_name']))
  13. {
  14. $guild_name = $row['guild_name'];
  15. }
  16. else
  17. {
  18. $guild_name = "(Brak)";
  19. }
  20.  
  21. echo "<tr>";
  22. echo "<td>".$row['name']."</td>";
  23. echo "<td>".$row['level']."</td>";
  24. echo "<td>".$guild_name."</td>";
  25. echo "<td>".$row['playtime']."</td>";
  26. echo "<td>".$row['last_play']."</td>";
  27. echo "</tr>";
  28. }
  29.  
  30. echo "</table>";
  31.  
  32. }


Najbardziej przekonuje mnie: http://www.phpfastcache.com/ jednak kompletnie nie wiem jak to zastosować w tej funkcji. Na ich stronie są przykłady jednak nie za bardzo wiem o co w nich biega.
Mam jeszcze 1 problem, w tej funkcji jest zapytanie które ma wyszukać dane graczy. Chciałbym aby wyszukał wszystkich graczy a nie tylko tych co są w gildii.

Byłbym bardzo wdzięczny gdybyś pokazał mi na przykładzie tej funkcji jak zastosować ten system cache.
Rysh
Którego dokładnie nie rozumiesz?
  1. <?php
  2. use phpFastCache\CacheManager;
  3. // auto, redis, cookie, files, sqlite, xcache, memcache, apc, memcached, wincache
  4.  
  5. $config = array(
  6. "storage" => "files",
  7. "path" => "/path/dir/to/your/cache",
  8. );
  9. CacheManager::setup($config);
  10. CacheManager::CachingMethod("phpfastcache");
  11.  
  12. $cache = CacheManager::getInstance();
  13.  
  14. // The getter, obviously, return your cache object
  15. $cache->get($keyword);
  16.  
  17. // The setter, for those who missed it, put 0 meant cache it forever
  18. $cache->set($keyword, $something_your_want_to_cache, $time_as_second = 0);
  19. ?>
Gruchol
Ten phpFastCache bez użycia nawet wywala mi mnóstwo błędów w dodatku chyba nie obsługuje zapytań mysqla.
Możesz polecić jakąś łatwą do ogarnięcia na początek bibliotekę?
daro0
No przecież można sobie napisać tylko prostą funkcję, po co od razu jakieś klasy:

https://kohanaframework.org/3.2/guide/api/Kohana_Core#cache

I jako data daje się tą tablicę którą zwróci zapytanie, nastąpi serializacja i zapis do pliku tekstowego, następnie odczyt i sprawdzanie po dacie i godzinie ostatniej modyfikacji czy jest ważna, jeśli tak to odczyt i deserializacja. Co w tym takiego trudnego?


Gruchol
Próbowałem napisać swoją funkcję ale to chyba nie ma sensu.
Wyszło mi coś takiego (nie działa warunek z time())

  1. global $db;
  2.  
  3. $file_name = "cache.txt";
  4. if(filemtime($file_name) > time() + 1*60)
  5. {
  6. $query_to_cache = $db->query("SELECT player.player.id, player.player.name, player.player.level, player.player.playtime, player.player.last_play, player.guild.name AS 'guild_name' FROM player.player, player.guild, player.guild_member WHERE player.player.id = player.guild_member.pid AND player.guild.id = player.guild_member.guild_id ORDER BY level DESC LIMIT 5");
  7. $query_to_cache->execute();
  8. $query_to_cache = $query_to_cache->fetch(PDO::FETCH_ASSOC);
  9.  
  10. $fp = fopen($file_name, 'w');
  11. fwrite($fp, print_r($query_to_cache, TRUE));
  12. fclose($fp);
  13. }


Jednak to nie ma sensu ;/
Bardzo bym prosił o pokazanie na przykładzie tego:

  1. function DisplayRanking()
  2. {
  3. global $db;
  4.  
  5. $info = $db->query("SELECT player.player.id, player.player.name, player.player.level, player.player.playtime, player.player.last_play, player.guild.name AS 'guild_name' FROM player.player, player.guild, player.guild_member WHERE player.player.id = player.guild_member.pid AND player.guild.id = player.guild_member.guild_id ORDER BY level DESC LIMIT 5");
  6. $info->execute();
  7.  
  8. echo "<table style='border: 1px solid;'>";
  9.  
  10. while($row = $info->fetch(PDO::FETCH_ASSOC))
  11. {
  12. if(!empty($row['guild_name']))
  13. {
  14. $guild_name = $row['guild_name'];
  15. }
  16. else
  17. {
  18. $guild_name = "(Brak)";
  19. }
  20.  
  21. echo "<tr>";
  22. echo "<td>".$row['name']."</td>";
  23. echo "<td>".$row['level']."</td>";
  24. echo "<td>".$guild_name."</td>";
  25. echo "<td>".$row['playtime']."</td>";
  26. echo "<td>".$row['last_play']."</td>";
  27. echo "</tr>";
  28. }
  29.  
  30. echo "</table>";
  31.  


jak cachować to zapytanie i później wyświetlać to w tabeli.
Niestety ciężko mi cokolwiek zrozumieć do czasu aż nie zobaczę czegoś na "żywym" przykładzie.
Oczywiście to nie jest jedyna funkcja którą będę musiał cachować, chcę na jej przykładzie zobaczyć tylko jak to działa.

Ogarnąłem już to cachowanie, bo znalazłem bardzo prostą bibliotekę.
Funkcja zwraca mi aktualnie tablice w tym stylu $dane[1][id];
I jak z takiej tablicy wyszukać dane po np. nazwie a nie po numerze tablicy?
Chodzi mi o coś w stylu $dane["Zenek"]["id"], czyli wyciągam id gracza Zenek.
daro0
No to masz tu (ale nie sprawdzałem działania kodu), może to zrozumiesz. I nie licz na gotowce, zresztą ograniczyłem tylko do jednego rekordu.

  1. define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR);
  2.  
  3. function DisplayRanking()
  4. {
  5. //najpierw sprawdzanie czy cache jest, jesli nie to pobieranie z bazy i zapis do cache
  6. if (($row = load_cache('ranking', 60)) === NULL)
  7. {
  8. $db = new PDO('mysql:host=localhost;dbname=test', 'root', 'qwerty123');
  9. $stmt = $db->prepare("SELECT player.player.id, player.player.name,
  10. player.player.level, player.player.playtime,
  11. player.player.last_play, player.guild.name AS 'guild_name'
  12. FROM player.player, player.guild, player.guild_member
  13. WHERE player.player.id = player.guild_member.pid
  14. AND player.guild.id = player.guild_member.guild_id
  15. ORDER BY level DESC LIMIT 1");
  16. $stmt->execute();
  17.  
  18. // jesli cokolwiek jest w bazie to zapis
  19. if ($row = $stmt->fetch(PDO::FETCH_OBJ))
  20. {
  21. save_cache('ranking', $row);
  22. }
  23. }
  24.  
  25. //jesli cokolwiek jest to wyswietl w tabeli
  26. if ($row)
  27. {
  28. display($row);
  29. }
  30.  
  31. }
  32.  
  33. function display($row)
  34. {
  35. echo "<table>";
  36.  
  37. if(!empty($row->guild_name))
  38. {
  39. $guild_name = $row->guild_name;
  40. }
  41. else
  42. {
  43. $guild_name = "(Brak)";
  44. }
  45.  
  46. echo "<tr>";
  47. echo "<td>".$row->name."</td>";
  48. echo "<td>".$row->level."</td>";
  49. echo "<td>".$guild_name."</td>";
  50. echo "<td>".$row->playtime."</td>";
  51. echo "<td>".$row->last_play."</td>";
  52. echo "</tr>";
  53.  
  54. echo "</table>";
  55. }
  56.  
  57. function save_cache($name, $data)
  58. {
  59. $file = sha1($name).'.cache';
  60. $dir = DOCROOT . 'cache' . DIRECTORY_SEPARATOR;
  61.  
  62. $data = serialize($data);
  63. return (bool) file_put_contents($dir.$file, $data, LOCK_EX);
  64.  
  65. }
  66.  
  67. function load_cache($name, $lifetime = 60)
  68. {
  69. $file = sha1($name).'.cache';
  70. $dir = DOCROOT . 'cache' . DIRECTORY_SEPARATOR;
  71.  
  72. // cache wazna jesli aktualny czas time() - czas ostatniej modyfikacji pliku
  73. // jest mniejszy od czasu zycia w sekundach
  74. if (is_file($dir.$file))
  75. {
  76. if ((time() - filemtime($dir.$file)) < $lifetime)
  77. {
  78. return unserialize(file_get_contents($dir.$file));
  79. }
  80. else // jesli nie, to usuwanie pliku jesli jest
  81. {
  82. unlink($dir.$file);
  83. }
  84. }
  85.  
  86. return NULL;
  87. }
  88.  
  89. // i wywolanie glownej funkcji
  90. DisplayRanking();
  91.  


Przeanalizuj to sobie jak to wszystko działa.
Gruchol
Tutaj lekko poprawiłem warunek bo wyrzucało błąd, że nie ma pliku:

  1. function load_cache($name, $lifetime = 60)
  2. {
  3. $file = sha1($name).'.cache';
  4. $dir = DOCROOT . 'cache' . DIRECTORY_SEPARATOR;
  5.  
  6. // cache wazna jesli aktualny czas time() - czas ostatniej modyfikacji pliku
  7. // jest mniejszy od czasu zycia w sekundach
  8. if (file_exists($dir.$file) AND (time() - filemtime($dir.$file)) < $lifetime)
  9. {
  10. return unserialize(file_get_contents($dir.$file));
  11. }
  12. elseif(file_exists($dir.$file)) // jesli nie, to usuwanie pliku jesli jest
  13. {
  14. unlink($dir.$file);
  15. }


Teraz próbuje przerobić aby wkładało wszystkie rekordy a nie tylko jeden lecz już nie mam pojęcia co z tym zrobić.
Próbowałem tak:
  1. while($row = $stmt->fetch(PDO::FETCH_ASSOC))
jednak nic nie chce ruszyć.
daro0
Sam zauważyłem ten błąd i też poprawiłem.

  1.  
  2. $query = "SELECT player.player.id, player.player.name,
  3. player.player.level, player.player.playtime,
  4. player.player.last_play, player.guild.name AS 'guild_name'
  5. FROM player.player, player.guild, player.guild_member
  6. WHERE player.player.id = player.guild_member.pid
  7. AND player.guild.id = player.guild_member.guild_id
  8. ORDER BY level DESC LIMIT 5";
  9.  
  10. if (($rows = load_cache($query, 60)) === NULL)
  11. {
  12. $db = new PDO('mysql:host=localhost;dbname=test', 'root', 'qwerty123');
  13. $stmt = $db->prepare($query);
  14. $stmt->execute();
  15.  
  16. $rows = $stmt->fetchAll(PDO::FETCH_CLASS, "stdClass");
  17. save_cache($query, $rows);
  18.  
  19. }
  20.  
  21. if ($rows !== NULL)
  22. {
  23. foreach ($rows as $row)
  24. {
  25. // wyswietlasz kazdy wiersz
  26. }
  27. }
  28.  


http://php.net/manual/en/pdostatement.fetchall.php

Zwróć uwagę że otrzymasz tablicę obiektów typu stdClass a jako nazwa cache powinno być to zapytanie, dlatego też zrobiłem inaczej.
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.