Что такое кэш второго уровня (L2 cache) в Hibernate?

Ответ

Кэш второго уровня (L2 cache) в Hibernate — это кэш сессий (SessionFactory), общий для всех сессий (Session), созданных из одной фабрики. Он хранит загруженные сущности и коллекции, что позволяет избежать повторных запросов к БД в разных транзакциях.

Отличие от кэша первого уровня (L1):

  • L1 cache привязан к конкретной сессии (Session) и живет только во время её существования.
  • L2 cache разделяется между всеми сессиями приложения.

Конфигурация и использование:

  1. Выбор провайдера кэша: Ehcache, Infinispan, Hazelcast, Caffeine.
  2. Включение в persistence.xml или hibernate.cfg.xml:
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
  3. Аннотирование сущностей:
    @Entity
    @Cacheable // Включает сущность в L2 cache
    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) // Стратегия
    public class Product { ... }

Стратегии согласованности (CacheConcurrencyStrategy):

  • READ_ONLY: для неизменяемых данных.
  • READ_WRITE: использует мягкие блокировки, обеспечивает согласованность для часто читаемых, но редко изменяемых данных.
  • NONSTRICT_READ_WRITE: обновления кэша после коммита транзакции, возможны краткие периоды несогласованности.
  • TRANSACTIONAL: полная поддержка транзакций (JTA), самая строгая.

Важные моменты:

  • Кэшируются только идентифицируемые сущности (с @Id). Запросы (Query) кэшируются отдельно (query cache).
  • При изменении данных через нативные SQL или другие приложения кэш может устареть — требуется инвалидация или использование стратегий с учетом этого.

Ответ 18+ 🔞

Да ты посмотри, какая тема подъехала — про кэш второго уровня в Hibernate! Ну это ж, блядь, целая эпопея, как у того Герасима с Муму, только тут не собаку топить, а запросы к базе оптимизировать. Слушай сюда, разжую.

Представь, L1 cache — это как твой личный холодильник в сессии. Открыл, взял пиво, закрыл. Никто, кроме тебя, туда не лазит. А L2 cache — это уже общий холодильник на всю хату, на все сессии от одной фабрики. Положил туда сущность — и любой другой чувак может её оттуда вытащить, не бегая каждый раз в магазин (то есть в базу данных). Удобно, ёпта!

Чем они вообще отличаются, эти кэши?

  • L1 (кэш первого уровня) — привязан к сессии (Session). Живёт, пока сессия жива. Умерла сессия — и кэш накрылся медным тазом. Всё, что в нём было, — тлен.
  • L2 (кэш второго уровня) — это уже статик, блядь, уровень фабрики (SessionFactory). Один на всех. Сущности там могут пережить не одну сессию, пока их не вытеснят или не инвалидируют.

Как это, сука, настроить?

  1. Выбрать провайдера. Их, блядь, овердохуища: Ehcache, Infinispan, Hazelcast... Выбирай, что душе угодно, как ту самую ткачиху из сказки.
  2. Включить в конфиге. Тыкаешь в persistence.xml или hibernate.cfg.xml нужные свойства. Смотри, не облажайся:
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
  1. Пометить сущности. Вот тут главное — не забыть аннотации, а то будет как с тем немым Герасимом: хочешь сказать, а нихуя не получается.
@Entity
@Cacheable // Говорит: "Эту сущность, блядь, можно кэшировать!"
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) // А тут стратегию выбираешь
public class Product { ... }

Про стратегии (CacheConcurrencyStrategy) — это отдельная песня:

  • READ_ONLY: Для данных, которые меняются реже, чем я в спортзал хожу. Только для чтения, идеально для справочников.
  • READ_WRITE: Самый частый гость. Использует мягкие блокировки. Подходит для данных, которые часто читают, но редко пишут. Согласованность есть, но не транзакционная, блядь.
  • NONSTRICT_READ_WRITE: Обновляет кэш уже после коммита транзакции. Могут быть микро-окна, когда в кэше лежит старый хуйня. Но зато быстрее.
  • TRANSACTIONAL: Полная, блядь, паранойя. Строгая транзакционность (JTA). Дорого, сложно, но если нужна абсолютная консистентность — то вот она.

А теперь, внимание, важные нюансы, про которые все забывают, как про ту царевну-лебедь:

  • Кэшируются только сущности с @Id. Запросы (Query) — это отдельная история, для них есть query cache, и его надо включать отдельно, ядрёна вошь!
  • Самый больной вопрос: а если данные поменяли в обход Hibernate? Напрямую SQL'ем или другое приложение? Кэш-то об этом не узнает и будет выдавать старьё. Тут либо инвалидацию делать, либо стратегии выбирать с учётом этого риска. Иначе будет как в том анекдоте: "И тут я охуел".

Короче, инструмент мощный, но, как и всё у нас на Руси, требует мозгов и понимания, что ты делаешь. А то настроишь READ_ONLY на часто обновляемые данные и потом будешь чесать репу: "Чё за хуйня? Данные не меняются!". В общем, думай, бошка, прежде чем тыкать.