Кешування другого рівня в Hibernate частина 2

Продовження розповід про кешування другого рівня в Hibernate. Розказується про те, які є реалізації кешу 2го рівня та які слід використовувати при протребі.

Кеш другого рівня в Hibernate може бути підключеним і може бути в межах процесу або кластера. Можуть бути різні реалізації кешу другого рівня, існують кілька вже готових реалізацій на основі готових движків кешування. Але можна реалізувати власний движок і підключити його за допомогою реалізації інтерфейсуorg.hibernate.cache.CacheProvider.

Визначають наступні провайдери кешу другого рівня:

EHCache. Підтримка кешування другого рівня в межах одного процесу однієї віртуальної машини або кластера. Може виконувати зберігання кешу як в оперативній памяті, так і на диск. Підтримує кешування запитів.

OSCache (OpenSymphony Cache). Підтримка кешування другого рівня в межах одного процесу однієї віртуальної машини. Підтримує кешування запитів.

SwarmCache. Підтримка кешування другого рівня в межах кластера. Не підтримує кешування запитів.

JBossCache. Підтримка кешування другого рівня в межах кластера. Підтримує кешування запитів.

Підтримка стратегій кешування залежить від кешу, а саме:

EHCache: Read-only, Read-write, Nonstrict-read-write

OSCache: Read-only, Read-write, Nonstrict-read-write

SwarmCache: Read-only, Nonstrict-read-write

JBossCache: Transactional

Підтримка кешування другого рівня в Hibernate

Кешування другого рівня в Hibernate потрібно увімкнути, для того, щоб його використовувати.

Увімкнути кешування другого рівня можна встановши property в конфігурації сесії Hibernate:

<property name="cache.use_second_level_cache">true</property>

Якщо необхідно увімкнути також кешування для запитів, то слід також встановити значення для property в конфігурації сесії Hibernate:

<property name="hibernate.cache.use_query_cache">true</property>

Також необхідно вказати клас провайдера кешування, а для цього треба задати наступний property в конфігурації сесії Hibernate:

— для провайдера EHCache

<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

— для провайдера OSCache

<property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property>

— для провайдера SwarmCache

<property name="cache.provider_class">org.hibernate.cache.SwarmCacheProvider</property>

Але для того, щоб кешування другого рівня було в дії, слід позначити хоча б один клас для кешування. Позначити певний клас для кешування можна двома способами:

  1. В описі маппінгу класу у файлі *.hbm.xml добавити елемент cache із відповідним значенням.
<class name="com.blogspot.javaua.sample.hibernate.Country" table="Country" mutable="false">
    <cache usage="read-only"/>
    …
  </class>

Вище описаний клас Country, який мапиться на таблицю Country. Ця таблиця є словником країн. Словник зміні не підлягає, тобто значення не добавляється, не редагується та не видаляється.вказує на те, що дані підлягають кешуванню, стратегія кешування read-only.

  1. У файлі конфігурації сесії hibernate.cfg.xml. Для цього використовується елемент <class-cache>, який наводиться після списку ресурсів. Ось як може описуватися кешування для класу Country:
<hibernate-configuration>
  <session-factory>
   …
   <mapping resource="com/blogspot/javaua/sample/hibernate/Country.hbm.xml"/>
    …
   <class-cache class="com.blogspot.javaua.sample.hibernate.Country" usage="read-only"/>
  </session-factory>
 </hibernate-configuration>

Я надаю перевагу конфігурації кешування другого рівня через файл hibernate.cfg.xml, оскільки так видно повний список класів, що підлягають кешуванню, а також при необхідності, можна легко відключити кешування.

Отже, ми розглянули, як включити кешування другого рівня, а також як вказати, які саме ентіті підлягають кешуванню. Ми не розглянули, як задається кешування для запитів.

Також ми не розглянули таке поняття, як регіони. Регіони – це так би мовити іменовані екземпляри кешу, в якому знаходяться різні класи із спільною політикою періоду існування, чи реалізації кешу тощо.По замовчуванню, ім’я регіону складає повна назва класу (якщо це кеш класу) або повна назва класу плюс імя property класу (якщо це колекція). За допомогою property сесії Hibernate hibernate.cache.region_prefix. Тоді ім’я регіону буде складатися із префіксу та повного імені класу. Вказати ім’я регіону можна явно за допомогою атрибутаregion в елементі або <class-cache>.

EHCache (http://ehcache.sourceforge.net)

Останнє обновлення аплікації це є ehcache-1.4-beta, яка вийшла 1 січня 2008. А це означає, що продукт не тільки живий, але і розвивається. Розповсюджується EhCache за ліцензією The Apache SoftwareLicense, Version 2.0. Спонсори там також далеко не з послідніх. Так що, проект живе і розвивається. Не може не радувати повна підтримка JSR107 (JCache API).

Серед вказаних характеристик слід відзначити:

— Простота (API є досить простим, початкова конфігурація також не є необхідною).

— Залежність тільки від commons-logging та commons-collections. Вони в свою чергу також поширюються за APL. Та й більшість проектів їх використовує. То ж, ця залежність не є проблематичною. Якщо використовуєть розприділенний кеш, то залежить також від JGroups або JMS.

— Кешування в оперативній пам’яті та на диск. Підтримка великих розмірів.

— Підтримка великої кількості кешів.

— Підтримка розширень для кешу (а також розширення для загружчиків та обробників виключень).

— А також багато чого іншого, про що ви можете точніше дізнатися за адресомhttp://ehcache.sourceforge.net/features.html

Як уже зазначено, можна і не конфігурувати EHCache. Але я не думаю, що це хороша ідея. Нам вона явно не підходить. Ми повинні навчитися конфігурувати EhCache.

Отже, конфігурація EHCache знаходиться у файлі ehcache.xml, який у свою чергу знаходиться в класспасі аплікації.

Отже, структура конфігураційного файла:

<ehcache>
   <diskStore …/>
   <defaultCache …/>
   <cache name="..." …/>
 </ehcache>

Конфігураційний файл може містити не тільки ці елементи, але й інші. Але вони розглядатися не будуть.

Роглянемо детальніше ці елементи.

/> — вказує шлях до каталогу, де файли кешу створюються.

Наступні значення є можливими:

— user.home – домашній каталог користувача;

— user.dir – текучий робочий каталог користувача;

— java.io.tmpdir – каталог тимчасових файлів.

Можна також вказувати субдиректорії, наприклад />

Конфігурація кешу, який не описаний за допомогою власного елемента, відбувається через.

<defaultCache
               maxElementsInMemory="10000"
               eternal="false"
               timeToIdleSeconds="120"
               timeToLiveSeconds="120"
               overflowToDisk="true"
               diskSpoolBufferSizeMB="30"
               maxElementsOnDisk="1000000"
               diskPersistent="false"
               diskExpiryThreadInternalSeconds="120"
               memoryStoreEvictionPolicy="LRU"/>

Можна також задавати конфігурацію для окремого кешу; а для цього використовується наступний елемент

<сache name="CacheName"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        maxElementsOnDisk="1000000"
        diskPersistent="false"
        diskExpiryThreadInternalSeconds="120"
        memoryStoreEvictionPolicy="LRU"/>

А тепер детальніше про кожен атрибут.

mame – назва кешу; назва, як ви вже, мабуть, зрозуміли має бути унікальна.

maxElementsInMemory – максимальна кількість об’єктів, які будуть створені та зберігатися в кеші в оперативній пам’яті.

maxElementsOnDisk – максимальна кількість об’єктів, які будуть збережені на диск.

eternal – вказує на те, чи є елементи вічними. Якщо вони є вічними, то будь-які настройки Idle та LiveSeconds ігноруються, елементи зберігаються до кінця.

timeToIdleSeconds – час життя невикористаного елемента кешу (за умови, якщо eternal рівний false). Якщо значення 0, то це значить, що елемент може залишатися в кеші в стані не використовуваного нескінченний період.

timeToLiveSeconds – час життя елемента кешу (за умови, якщо eternal рівний false). Якщо значення 0, то це значить, що елемент може залишатися в кеші в стані невикористаного нескінченний період.

overflowToDisk – вказує на те, чи зберігати елементи на диск, якщо досягнуто максимуму елементів в пам’яті.

diskPersistent — чи зберігаються закешовані дані між пере запусками віртуальної машини. Значення по-замовчуванню false.

diskExpiryThreadInternalSeconds – кількість секунд, через які відбувається запуск потоку очищення диску від елементів кешу, що завершили свій час життя.

memoryStoreEvectionPolicy. Розрізняються наступні політики LRU – Least Recently Used, FIFO – First In First Out, LFU – Last Frequently Used.

Приклад аплікації із використанням кешу EHCache.

Отже, розглянуто трохи теорії, а тепер ближче до практики. Для цього було створено просту аплікацію, яка містить 4 доменних об’єкта: Country, Materials, Product, ProductMaterial.

Отже, ми маємо аплікацію, яка містить інформацію про матеріали (назва, код, ціна, країна виробник), про продукцію (назва, код, ціна, країна виробник, матеріали із яких виготовлена продукція) і власне словник країн виробників.

Кешування класів та стратегії кешування описані у файлі hibernate.cfg.xml.

Отже, hibernate.cfg.xml має вигляд:

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.url">jdbc:mysql://localhost/proregister</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password"/>
    <property name="hibernate.show_sql">false</property>

    <mapping resource="com/blogspot/javaua/sample/proregister/objects/Country.hbm.xml"/>
    <mapping resource="com/blogspot/javaua/sample/proregister/objects/Material.hbm.xml"/>
    <mapping resource="com/blogspot/javaua/sample/proregister/objects/Product.hbm.xml"/>
    <mapping resource="com/blogspot/javaua/sample/proregister/objects/ProductMaterial.hbm.xml"/>

    <class-cache class="com.blogspot.javaua.sample.proregister.objects.Country" usage="read-only"/>
    <class-cache class="com.blogspot.javaua.sample.proregister.objects.Material" usage="read-write"/>
    <class-cache class="com.blogspot.javaua.sample.proregister.objects.Product" usage="read-write"/>
    <class-cache class="com.blogspot.javaua.sample.proregister.objects.ProductMaterial" usage="read-write"/>
  </session-factory>
 </hibernate-configuration>

Клас Country має стратегію кешування read-only, в той час як всім іншим задана стратегія read-write.Country є по факту незмінним словником країн; його не можна змінювати.

Кеши класів Material, Product та ProductMaterial повинні підтримувати зміну, оскільки елементи можуть як добавлятися, так і редагуватися та видалятися. Саме тому їм задана стратегія read-write.

Аплікація працюватиме із базою даних на одній машині, тому виконувати кешування на диск немає потреби. Окрім того, кількість даних є невеликою, тому їх можна спокійно зберігати в базу даних.

Для детальної конфігурації EHCache потрібно конфігурувати кожен кеш у файлі ehcache.xml.

Отже, конфігурація має наступний вигляд:

<ehcache>
   <diskStore path="java.io.tmpdir"/>

   <defaultCache
                 maxElementsInMemory="10000"
                 eternal="false"
                 timeToIdleSeconds="120"
                 timeToLiveSeconds="120"
                 overflowToDisk="false"
                 diskPersistent="false"
                 diskExpiryThreadIntervalSeconds="120"
                 memoryStoreEvictionPolicy="LRU"/>

     [тут має бути конфігурація кешів, розглянута дальше]

 </ehcache>

Отже, ми вказали на каталог для файлів кешування та конфігурацію кешу по-замовчуванню.

Нижче подана конфігурація кешу для класу Country. Задаємо максимальну кількість елементів в пам’яті, забороняється записувати дані на диск, дані можуть зберігатися тривалий час. Якщо кількість елементів в пам’яті перевищує 200, то тоді відбувається очистка кешу.

<cache name="com.blogspot.javaua.sample.proregister.objects.Country"
        maxElementsInMemory="200"
        eternal="true"
        overflowToDisk="false"/>

Настройка кешу для об’єктів Product, Material та ProductMaterial має відмінності, оскільки ці об’єкти можуть змінюватися, тому для них задана конфігурація тривалості існування елементів кешу. Конфігурація подана нижче.

<cache name="com.blogspot.javaua.sample.proregister.Product"
        maxElemenentsInMemory="2000"
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="300"/>
 <cache name="com.blogspot.javaua.sample.proregister.Material"
        maxElemenentsInMemory="5000"
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="240"
        timeToLiveSeconds="300"/>
 <cache name="com.blogspot.javaua.sample.proregister.ProductMaterial"
        maxElemenentsInMemory="10000"
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"/>

Як бачите, для різних кешів задана різна кількість елементів в памяті. Атрибут eternal має значення false, тому конфігурація періоду існування елементів у кеші не буде ігноруватися. Дані не зберігаються на диск для жодного із кешів, використовуваних в аплікації.

Отже, ми розглянули які існують провайдери кешу другого рівня для Hibernate, також ми розглянули, як настроїти Hibernate для використання кешу другого рівня для класів (проте не зачепили теми кешування запитів та колекцій). Розглянуто було також більш детально провайдер EHCache.

Оригінал статті був написаний більш, ніж півтора року тому, тому декотра інформація може бути застарілою. Я спробував обновити декотру інформацію, так, наприклад, EHCache тепер є повноцінно розприділеним.

Стаття опублікована вперше по адресу http://java-ua.blogspot.com/2007/12/hibernate.html

Коментарі 1

zenyk - 02 червня 2009, 14:01

хороша серія статей.

btw, ніхто часом не пробував використовувати для кешу другого рівня зовнішні сервери? наприклад той самий ehcache, але на іншій машині?

які нюанси можуть бути в такому випадку?

Коментувати
© 2009 - 2020, Розробка - соціальна ІТ спільнота.
Контакти: info@rozrobka.com
Правила користування