← Назад к вопросам

Как предотвратить кэширование базы?

1.0 Junior🔥 81 комментариев
#Soft Skills

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как предотвратить кэширование базы данных

Кэширование базы данных — важный аспект оптимизации приложений. Иногда нужно явно контролировать или отключать кэш для обеспечения актуальности данных. Рассмотрим различные подходы и решения.

Основные способы контроля кэширования

1. Инвалидация кэша на уровне приложения

При использовании Redis или Memcached можно явно очищать кэш при изменении данных:

import redis

cache = redis.Redis(host="localhost", port=6379)

def get_user(user_id):
    cache_key = f"user:{user_id}"
    cached = cache.get(cache_key)
    
    if cached:
        return json.loads(cached)
    
    user = db.query(User).filter_by(id=user_id).first()
    cache.setex(cache_key, 3600, json.dumps(user.to_dict()))
    return user

def update_user(user_id, data):
    user = db.query(User).filter_by(id=user_id).first()
    # ... обновление данных ...
    db.commit()
    
    # Инвалидируем кэш
    cache.delete(f"user:{user_id}")

2. TTL (Time To Live) с коротким временем жизни

Устанавливайте разумные сроки действия кэша в зависимости от требований приложения:

def cache_with_ttl(key, func, ttl=300):
    """Кэширование с контролируемым TTL"""
    cached = cache.get(key)
    if cached:
        return json.loads(cached)
    
    result = func()
    cache.setex(key, ttl, json.dumps(result))
    return result

# Для критичных данных — минимальный TTL
recent_data = cache_with_ttl("critical_data", fetch_data, ttl=10)

# Для менее критичных — больший TTL
static_data = cache_with_ttl("static_data", fetch_static, ttl=3600)

3. Отключение кэша в SQLAlchemy

При работе с ORM можно отключать кэширование сессии:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# Отключаем кэширование запросов
engine = create_engine("postgresql://...", 
                       echo=False,
                       pool_pre_ping=True)

Session = sessionmaker(bind=engine)
session = Session()

# Явно требуем свежие данные
user = session.query(User).filter_by(id=1).first()
session.expire(user)  # Инвалидируем объект в кэше сессии

# Или создаём новую сессию для каждого запроса
with Session() as new_session:
    user = new_session.query(User).filter_by(id=1).first()

4. HTTP-кэширование и заголовки

Контролируйте браузерный и промежуточный кэш через HTTP-заголовки:

from flask import Flask, Response

app = Flask(__name__)

@app.route("/api/data")
def get_data():
    data = fetch_from_db()
    
    response = Response(json.dumps(data), mimetype="application/json")
    # Запрещаем любое кэширование
    response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "0"
    
    return response

# Или позволяем кэширование на короткий период
@app.route("/api/static-data")
def get_static():
    data = fetch_static_data()
    response = Response(json.dumps(data), mimetype="application/json")
    response.headers["Cache-Control"] = "public, max-age=60"  # 60 секунд
    return response

5. Использование функции skip_cache в ORM

from sqlalchemy.orm import with_entities

# Обход кэша SQLAlchemy
query = session.query(User).filter(User.id == 1)
query = query.execution_options(synchronize_session=False)

# Или использование raw SQL при необходимости актуальности
from sqlalchemy import text

result = session.execute(
    text("SELECT * FROM users WHERE id = :user_id"),
    {"user_id": 1}
)

6. Кэш-буста версионирование

Явное управление версиями кэша через параметры:

def get_cached_with_version(resource_id, version=None):
    cache_key = f"resource:{resource_id}:v{version or "latest"}"
    
    cached = cache.get(cache_key)
    if cached:
        return json.loads(cached)
    
    data = fetch_from_db(resource_id)
    cache.setex(cache_key, 3600, json.dumps(data))
    return data

# При обновлении данных увеличиваем версию
def update_resource(resource_id):
    # ... обновление ...
    cache.delete(f"resource:{resource_id}:v*")  # Очищаем все версии

Рекомендации

  • Минимальный TTL для критичных данных (0-10 сек)
  • Инвалидация при каждом изменении в БД
  • Мониторинг попаданий/промахов кэша
  • Tag-based кэширование для групповой инвалидации
  • Separation of concerns — разные TTL для разных типов данных

Правильное управление кэшем обеспечивает баланс между производительностью и актуальностью данных.

Как предотвратить кэширование базы? | PrepBro