Ниже — задачка по работе с двухуровневым кешем (БД + 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', )

Нет Ответов