Implementando um sistema de cache com JSON, PHP e MySQL

Veja como acelerar o acesso ao MySQL com o uso de cache em arquivo JSON

08/03/2024

Implementando um sistema de cache com JSON, PHP e MySQL

Implementando um sistema de cache com JSON, PHP e MySQL

Introdução

Este artigo mostra uma forma simples de acelerar a consulta ao banco de dados MySQL em seu site. Para atingir este objetivo, utilizaremos JSON para gravar os dados em cache.

Essa técnica ajuda a evitar consultas repetidas, tornando o seu site mais ágil e melhorando a experiência dos visitantes.

Recomendações

Se você está enfrentando lentidão nas suas consultas MySQL, a implementação de um sistema de cache pode ser uma solução eficaz. No entanto, antes de prosseguir, é crucial verificar alguns aspectos que podem melhorar a performance das suas consultas de maneira significativa:

  • Utilize o host localhost para a conexão se o seu banco de dados MySQL estiver no mesmo servidor que o seu site. Isso pode reduzir o tempo de resposta, pois a comunicação é feita internamente no servidor, evitando atrasos de rede.
  • Verifique se as tabelas têm os relacionamentos corretos. Relacionamentos bem definidos e estruturados entre as tabelas são fundamentais para consultas eficientes.
  • Certifique-se de que os campos frequentemente usados em cláusulas ORDER BY e WHERE estão corretamente indexados. Índices bem projetados são essenciais para aumentar a velocidade de consultas em grandes volumes de dados.

Adotando essas práticas, você pode otimizar o desempenho do seu banco de dados antes de considerar o cache, garantindo que a infraestrutura de dados esteja configurada para adequadamente.

Código de Exemplo

Para ilustrar o uso eficiente do cache, o código abaixo foi escolhido como exemplo. Ele aborda a otimização da listagem de categorias de produtos em um site de comércio eletrônico, onde estas são ordenadas pela quantidade de vendas. Esta funcionalidade, apesar de crucial para destacar os produtos mais populares, pode se tornar extremamente lenta à medida que o volume de dados e transações da loja aumenta.

A consulta necessária para obter essas informações do banco de dados é complexa, pois envolve a agregação e ordenação de dados baseados em vendas, o que exige uma quantidade significativa de recursos computacionais, especialmente se for feita frequentemente. Ao implementar um sistema de cache que armazena o resultado dessa consulta em um arquivo JSON, reduzimos drasticamente o número de acessos ao banco de dados para essas informações, reduzindo a carga de processamento no servidor e acelerando o tempo de resposta do site.

<?php
// Configurações do Banco de Dados
$host = 'localhost';
$db   = 'nome_do_banco';
$user = 'usuario';
$pass = 'senha';
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
    throw new \PDOException($e->getMessage(), (int)$e->getCode());
}

function verificarCache($cacheFile, $cacheTime) {
    if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTime)) {
        return json_decode(file_get_contents($cacheFile), true);
    }
    return false;
}

function atualizarCache($pdo, $cacheFile) {
    $sql = "SELECT c.id, c.nome AS nome_categoria
            FROM categorias c
            JOIN produtos p ON c.id = p.categoria_id
            JOIN vendas v ON p.id = v.produto_id
            WHERE p.quantidade_em_estoque > 0
            GROUP BY c.id
            ORDER BY SUM(v.quantidade) DESC";

    $stmt = $pdo->query($sql);
    $categorias = $stmt->fetchAll(PDO::FETCH_ASSOC);
    if (!is_dir('./cache/')) {
        mkdir('./cache/', 0777, true);
    }
    file_put_contents($cacheFile, json_encode($categorias));
    return $categorias;
}

function obterCategorias($pdo, $cacheFile, $cacheTime) {
    $categorias = verificarCache($cacheFile, $cacheTime);
    if ($categorias === false) {
        $categorias = atualizarCache($pdo, $cacheFile);
    }
    return $categorias;
}

// Uso das funções
$cacheFile = './cache/categorias_produtos_vendas.json';
$cacheTime = 3600; // Tempo de cache em segundos (1 hora)
$categorias = obterCategorias($pdo, $cacheFile, $cacheTime);

// Exibindo categorias
foreach ($categorias as $categoria) {
    echo '<a href="categoria.php?id=' . $categoria['id'] . '">' . htmlspecialchars($categoria['nome_categoria']) . '</a><br>';
}
?>

Requisitos

Para que este script funcione no seu ambiente, é essencial que sua instalação do PHP tenha as extensões pdo_mysql e json ativadas.

Se o seu site estiver hospedado na MCO2, fique tranquilo, pois nossos servidores já possuem todas as extensões necessárias para a execução do script sem problemas. Confira nossos planos de hospedagem.

Explicando o Código

Nesta seção, vamos detalhar cada parte do código para entender como ele funciona. O exemplo fornecido ilustra a conexão com um banco de dados, a criação de um sistema de cache e como esses elementos interagem para melhorar o desempenho de uma aplicação web. Acompanhe os próximos itens para descobrir como cada segmento do código contribui para essa funcionalidade.

Configurações do Banco de Dados

Este trecho inicializa a conexão com o banco de dados MySQL usando PDO. Definimos as configurações básicas como host, nome do banco, usuário e senha. Além disso, especificamos o charset como 'utf8mb4' para suportar caracteres Unicode completos, incluindo emojis. A variável $dsn contém a string de conexão usada para estabelecer a conexão com o banco.

$host = 'localhost';
$db   = 'nome_do_banco';
$user = 'usuario';
$pass = 'senha';
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";

Tratamento de Exceções

Aqui, tentamos estabelecer a conexão com o banco de dados dentro de um bloco try. Se algo der errado, o PHP lançará uma exceção PDOException. Usamos o catch para capturar essa exceção e lançar novamente, exibindo a mensagem de erro e o código de erro correspondente. Isso ajuda a identificar problemas na conexão de forma mais clara.

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
    throw new \PDOException($e->getMessage(), (int)$e->getCode());
}

Função verificarCache

Esta função verifica se um arquivo de cache existe e se ainda é válido, baseando-se no tempo definido. Se o arquivo de cache está atualizado, ele retorna os dados decodificados de JSON para PHP. Isso reduz a necessidade de consultas frequentes ao banco de dados, utilizando os dados armazenados no cache quando disponível.

function verificarCache($cacheFile, $cacheTime) {
    if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTime)) {
        return json_decode(file_get_contents($cacheFile), true);
    }
    return false;
}

Função atualizarCache

Esta função é chamada quando o cache está desatualizado ou não existe. Ela executa uma consulta SQL para obter as categorias de produtos baseadas em sua disponibilidade em estoque e a quantidade vendida. Após realizar a consulta, os resultados são salvos em um arquivo de cache no formato JSON. Isso permite que a aplicação utilize os dados do cache em vez de realizar novas consultas ao banco de dados, otimizando o desempenho.

function atualizarCache($pdo, $cacheFile) {
    $sql = "SELECT c.id, c.nome AS nome_categoria
            FROM categorias c
            JOIN produtos p ON c.id = p.categoria_id
            JOIN vendas v ON p.id = v.produto_id
            WHERE p.quantidade_em_estoque > 0
            GROUP BY c.id
            ORDER BY SUM(v.quantidade) DESC";
    
    $stmt = $pdo->query($sql);
    $categorias = $stmt->fetchAll(PDO::FETCH_ASSOC);
    if (!is_dir('./cache/')) {
        mkdir('./cache/', 0777, true);
    }
    file_put_contents($cacheFile, json_encode($categorias));
    return $categorias;
}

Função obterCategorias

Esta função gerencia o acesso às categorias de produtos, preferencialmente através do cache, para minimizar o acesso ao banco de dados. Primeiramente, verifica se os dados desejados já estão disponíveis no cache e ainda são válidos. Se sim, os dados do cache são usados. Caso contrário, a função `atualizarCache` é chamada para obter dados atualizados do banco de dados e atualizar o cache. Esse processo garante que o site responda rapidamente, melhorando a experiência do usuário ao reduzir o tempo de carregamento das páginas.

function obterCategorias($pdo, $cacheFile, $cacheTime) {
    $categorias = verificarCache($cacheFile, $cacheTime);
    if ($categorias === false) {
        $categorias = atualizarCache($pdo, $cacheFile);
    }
    return $categorias;
}

Obtendo e Exibindo as Categorias

Primeiro, especificamos o arquivo de cache ($cacheFile) e o tempo de vida do cache ($cacheTime). A função obterCategorias verifica se o cache é válido; se não, atualiza-o com dados do banco. Usamos essas informações para exibir as categorias disponíveis, cada uma como um link para mais detalhes, garantindo a segurança com htmlspecialchars.

$cacheFile = './cache/categorias_produtos_vendas.json';
$cacheTime = 3600; // 1 hora
$categorias = obterCategorias($pdo, $cacheFile, $cacheTime);

foreach ($categorias as $categoria) {
    echo '<a href="categoria.php?id=' . $categoria['id'] . '">' . htmlspecialchars($categoria['nome_categoria']) . '</a><br>';
}

Observações Importantes

Ao implementar um sistema de cache para melhorar o desempenho da sua aplicação, lembre-se destas dicas importantes:

  • Segurança dos Dados do Cache: Para evitar vazamentos de informações, nunca armazene arquivos de cache contendo dados sensíveis em diretórios acessíveis publicamente. Mantenha esses arquivos em locais seguros e inacessíveis via navegador.
  • Atualização do Cache: O tempo de vida do cache deve ser configurado de acordo com a frequência de atualização dos dados. Isso garante que os usuários tenham acesso a informações precisas e atuais.
  • Gerenciamento do Cache em Áreas Administrativas: Se sua aplicação possui uma área administrativa que permite a gestão de dados, como edição de categorias, implemente uma funcionalidade para remover ou atualizar o cache automaticamente quando essas alterações ocorrerem. Isso assegura que as modificações se reflitam imediatamente para os usuários, mantendo a eficácia do cache sem sacrificar a precisão dos dados.

Este artigo nas redes sociais: Facebook, Twitter/X, LinkedIn, Telegram, Pinterest, Tumblr, Flipboard, Mastodon

Domínios hospedados
Clientes satisfeitos