🐻 Медведи — известные мастера организации запасов. Они прячут мёд и ягоды в разных местах, чтобы зимой не остаться голодными. Но что, если в пещере места недостаточно, а запасы устаревают? Точно так же работает кэширование в Hibernate. Медведи пользуются разными уровнями кэша, чтобы ускорить "доступ к еде" (данным), но иногда из-за устаревших запасов возникают конфликты.
1. Первый уровень кэша (Session)
🐾 Медведь организовал корзинку (Session), куда кладёт ягоды сразу, как только находит их в лесу. Если он вдруг хочет перекусить, то сначала смотрит в корзину — там ли уже есть ягода? Если нет, идёт снова в лес (запрос в базу данных).
Ключевые моменты:
Hibernate автоматически кэширует объекты в пределах сессии.
Этот кэш активен только для одного медведя (одной транзакции).
Он не делится с другими медведями.
🛠 Пример:
Session session = sessionFactory.openSession();
Product product = session.get(Product.class, 1); // Запрашиваем из корзины (кэша)
session.close(); // Корзина исчезает
Кроме get(), Hibernate может использовать load(), который создаст прокси объекта и выполнит запрос только при первом обращении к полям.
2. Второй уровень кэша (SessionFactory)
🐻 Медведи решили организовать общий склад, чтобы экономить усилия. Теперь, если мёд уже лежит на складе, они берут его оттуда, не ходя в лес.
Ключевые моменты:
Кэш на уровне SessionFactory — это как общий склад, доступный всем медведям (глобальный кэш для всех сессий).
Этот кэш доступен для всех медведей (всех транзакций).
Требует настройки внешних инструментов (EHCache, Infinispan).
Но! Если ягоды испортились, а никто не проверил, это может привести к проблемам (устаревшие данные).
🛠 Пример:
<hibernate-configuration>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
</hibernate-configuration>
Кейс 1:
// Медведь 1
Session session1 = sessionFactory.openSession();
Transaction tx1 = session1.beginTransaction();
Product product1 = session1.get(Product.class, 1);
product1.setName("Fresh Honey");
session1.update(product1);
tx1.commit();
session1.close();
// Медведь 2
Session session2 = sessionFactory.openSession();
Product product2 = session2.get(Product.class, 1); // Увидит старые данные!
System.out.println(product2.getName()); // Старое значение
session2.close();
Решение:
Используйте механизм инвалидации на уровне SessionFactory , чтобы изменения стали доступны .
sessionFactory.getCache().evict(Product.class, 1); // Удаляем старую версию объекта
Кейс 2: медведи хранят слишком много мёда, из-за чего склад переполняется и возникает проблема нехватки памяти.
Решение: настройте стратегию очистки (eviction) в зависимости от потребностей. Используйте внешние кэш-менеджеры, например EHCache, Infinispan, или Redis.
Пример настройки EHCache:
<cache name="com.example.Product"
maxEntriesLocalHeap="1000"
timeToLiveSeconds="3600" />
Кейс3: медведи работают в кластере (распределённая архитектура), но данные кэша устаревают из-за отсутствия синхронизации.
Решение:
Используйте распределённые кэши, такие как Infinispan или Hazelcast.
Настройте синхронизацию:
hibernate.cache.region.factory_class = org.infinispan.hibernate.cache.v60.InfinispanRegionFactory
hibernate.infinispan.statistics = true
Кейс4: фантомные данные (добавленные записи не видны в результате кэшированного запроса). Два медведя работают с одной и той же доской задач. Один медведь завершает задачу и вычёркивает её из списка.
Второй медведь пытается выполнить задачу, которая уже вычеркнута, но видит старый список (фантомные данные).
Решение: включите обновление кэша при вставке новых данных.
sessionFactory.getCache().evictQueryRegion("ProductQuery");
3. Запросы кэша (Query Cache)
🐻 Иногда медведи помнят не только запасы, но и "списки", где указано, сколько ягод нужно собрать с каждого куста. Этот механизм позволяет кэшировать результаты запросов.
🛠 Пример:
Query query = session.createQuery("FROM Product WHERE category = :category");
query.setCacheable(true); // Включаем кэширование для запроса
query.setParameter("category", "honey");
List<Product> products = query.list();
4. Когда медведям лучше не пользоваться кэшами
🐻 Если медведи пытаются запастись всем подряд, это может привести к хаосу. Некоторые данные проще запрашивать из леса напрямую (базы данных), чем поддерживать их свежесть в кэше.
Примеры:
- Часто меняющиеся данные.
- Ограниченная память на складе.
Вывод
🐾 Для кратковременных запасов — корзины (Session).
🐾 Для долгосрочных — склады (Second Level Cache).
🐾 Для списка задач — записи о кустах (Query Cache).
Но они помнят, что любые запасы требуют правильного управления и проверки, иначе последствия могут быть катастрофическими.
Медведи научились использовать кэши эффективно, будь как медведи!
Top comments (0)