Ниже — задачка по работе с двухуровневым кешем (БД + redis) на php, которую мне нужно было решить за ~20 минут отведенного времени.
Дано:
три хранилища:
-
база данных (mysql),
-
кэш (redis)
-
API (http)
Необходимо:
-
по id пользователя вернуть данные из хранилища
Условия:
-
Если данные есть в кэше — вернуть из кэша.
-
Если данных в кэше нет, то взять из базы, затем закэшировать и вернуть.
-
Если данных нет ни в кэше, ни в базе, то взять из API, сохранить в базе, закэшировать и вернуть.
-
В API данные есть всегда.
Реализовывать подключения к хранилищам и непосредственно запросы к ним не нужно, достаточно пустых методов в классах.
Решение:
Сгенерировано нейронкой ChatGpt 3.5 (с моими доработками ниже)
Комментарий ИИ:
В этом примере класс
DataRetriever
отвечает за получение данных из трех хранилищ. Если данные есть в кэше, они возвращаются сразу. Если данных нет в кэше, они извлекаются из базы данных, сохраняются в кэше и затем возвращаются. Если данных нет ни в кэше, ни в базе данных, они запрашиваются из API, сохраняются в базе данных и кэше, и затем возвращаются.Обратите внимание, что в этом примере я использовал пустые методы для подключений к хранилищам и запросов к ним. Вам нужно будет реализовать эти методы с учетом вашей конкретной среды выполнения и используемых инструментов (например, использовать соответствующие библиотеки для работы с
MySQL, Redis и HTTP
).
<?php class Database { public function getDataFromDatabase($userId) { // Подключение к базе данных и выполнение запроса // Возвращает данные пользователя из базы данных } } class Cache { public function getDataFromCache($userId) { // Подключение к кэшу и получение данных по ключу $userId // Возвращает данные пользователя из кэша } public function cacheData($userId, $data) { // Подключение к кэшу и сохранение данных по ключу $userId } } class API { public function getDataFromAPI($userId) { // Подключение к API и получение данных пользователя по id // Возвращает данные пользователя из API } } class DataRetriever { private $database; private $cache; private $api; public function __construct(Database $database, Cache $cache, API $api) { $this->database = $database; $this->cache = $cache; $this->api = $api; } public function getData($userId) { $data = $this->cache->getDataFromCache($userId); if (!$data) { $data = $this->database->getDataFromDatabase($userId); if (!$data) { $data = $this->api->getDataFromAPI($userId); $this->database->saveDataToDatabase($userId, $data); } $this->cache->cacheData($userId, $data); } return $data; } } // Пример использования $database = new Database(); $cache = new Cache(); $api = new API(); $dataRetriever = new DataRetriever($database, $cache, $api); $userId = 123; $data = $dataRetriever->getData($userId); // Используем данные пользователя echo "Данные пользователя: " . $data;
Дорабатываем до рабочей (демо) версии:
-
добавляем интерфейс для источников данных (т.к. по сути операции у них одинаковые)
-
добавляем вероятность получения данных из источников через трейт
-
добавляем примеры демо- данных (для проверки)
<?php /** * Генератор случайных данных */ trait RandomGen { public function getRandomExist() { return (rand(0, 2) == 2); } } /** * Единый интерфейс под разные источники данных */ interface DataSource { public function getUserData(int $userId): ?array; public function saveUserData(int $userId, array $data): bool; } /** * Источник данных - База данных */ class DatabaseSource implements DataSource { use RandomGen; public function getUserData(int $userId): ?array { // Подключение к базе данных и выполнение запроса // Возвращает данные пользователя из базы данных if($this->getRandomExist()) { return [$userId, 'nameFromDB']; } return null; } public function saveUserData(int $userId, array $data): bool { // сохранение даных в БД return true; } } /** * Источник данных - Кеш */ class CacheSource implements DataSource { use RandomGen; public function getUserData($userId): ?array { // Подключение к кэшу и получение данных по ключу $userId // Возвращает данные пользователя из кэша if($this->getRandomExist()) { return [$userId, 'nameFromCache']; } return null; } public function saveUserData($userId, $data): bool { // Подключение к кэшу и сохранение данных по ключу $userId return true; } } /** * Источник данных - API */ class ApiSource implements DataSource { use RandomGen; public function getUserData($userId): ?array { // Подключение к API и получение данных пользователя по id // Возвращает данные пользователя из API if($this->getRandomExist()) { return [$userId, 'nameFromAPI']; } return null; } public function saveUserData($userId, $data): bool { // Сохранение данных в АПИ return true; } } class DataRetriever { private $database; private $cache; private $api; public function __construct(DatabaseSource $database, CacheSource $cache, ApiSource $api) { $this->database = $database; $this->cache = $cache; $this->api = $api; } /** * Get user data * @param int $userId * @return array|null */ public function getUserData(int $userId) { $data = $this->cache->getUserData($userId); if (!$data) { $data = $this->database->getUserData($userId); if (!$data) { $data = $this->api->getUserData($userId); if($data) { $this->database->saveUserData($userId, $data); } } $this->cache->saveUserData($userId, $data); } return $data; } } ////////////////////////////////////////////////////////////////////////////////// // Пример использования $database = new DatabaseSource(); $cache = new CacheSource(); $api = new ApiSource(); $dataRetriever = new DataRetriever($database, $cache, $api); for($userId = 1; $userId < 10; $userId++) { $data = $dataRetriever->getUserData($userId); // Используем данные пользователя echo "Данные пользователя: #$userId: " . var_export($data, 1) . "nn"; }
Результат работы:
php index.php
Данные пользователя: #1: array ( 0 => 1, 1 => 'nameFromAPI', ) Данные пользователя: #2: array ( 0 => 2, 1 => 'nameFromDB', ) Данные пользователя: #3: array ( 0 => 3, 1 => 'nameFromAPI', ) Данные пользователя: #4: array ( 0 => 4, 1 => 'nameFromCache', ) Данные пользователя: #5: array ( 0 => 5, 1 => 'nameFromCache', ) Данные пользователя: #6: array ( 0 => 6, 1 => 'nameFromDB', Данные пользователя: #9: array ( 0 => 9, 1 => 'nameFromAPI', )
Нет Ответов