Частина I: Трохи теорії
Є багато способів пришвидшити роботу Hibernate. Одним із них є кешування другого рівня (second level cache).
Для мене він знадобився при оптимізації роботи проекту, який використовує Hibernate 3.2.3. В межах аплікації використовується кілька наборів даних, які рідко змінюються. Декотрі дані взагалі не змінюються. Витягувати їх із бази даних кожен раз виходить доволі накладно і навіть довго. Після використання кешування, на звичайній машині різниця почала відмічатися одразу ж.
Взагалі про розгляді кешування в Hibernate, слід розрізняти кешування першого та другого рівнів. Кешування першого рівня є обовязковим, його не можна відключити. Це є кешування рівня одиниці виконання роботи (unit of work) і виконується воно через Session.
Трохи детальніше про кешування першого рівня, адже воно є необхідним для розуміння кешування другого рівня. Перш за все, слід зрозуміти, що це є кешування перстистетних об'єктів, тобто, в межах однієї Session, кешуються об’єкти класу, а не окремі дані, і отримуються для одного і того самого же рядка в базі даних один і той самий об'єкт. Що ж це дає, і чому зрозблено саме так? По-перше, це дозволяє виконувати ідентифікацію по об’єкту, а не по значенню в межах однієї сесії. По-друге, це дозволяє зберігати інформацію про зміни до рядку в межах одного об’єкта, що уже спасає від будь-яких подальших проблем пов’язаних із синхронізацією із базою даних. Отже, кешування першого рівня, використовується в межах сесії одного користувача, і не впливає на роботу інших користувачів. Це пришвидшує роботу.
Кешування другого рівня має зовсім інші межі використання. Навідміну від кешування першого рівня (яке використовується в межах запиту користувача або бізнес транзакції користувача), кешування другого рівня використовується в межах процесу або кластера виконання аплікації. Цей кеш є спільним для багатьох користувачів системи, відповідно, його потрібно осторожно використовувати, та володіти основними правилами.
Перш за все, слід сказати, що кеш другого рівня в Hibernate може мати межі процесу або кластера. Всі сесії використовують спільний кеш. Фактично кеш другого рівня має межі SessionFactory, в той час як кеш першого рівня має межі Session.
Для того, щоб робота кешу другого рівня була задовільною в багатокористувацькому середовищі, слід розуміти стратегії кешування. Стратегія кешування для об’єкта кешування встановлюється незалежно.
Так виділяють наступні стратегії кешування:
- read-only – для об’єктів, що не змінюються ніколи в межах роботи аплікації.
Типове для використання у випадку, якщо значення об’єктів не змінюється в процесі роботи аплікації (наприклад, ролі користувачів, список країн, мов, інші специфічні словники). Для подібних об’єктів можна також використовувати mutable = “false”, що дозволяє Hibernate пришвидшувати роботу для незмінюваних об’єктів.
- read-write – для об’єктів, що можуть змінюватися в межах роботи аплікації, але частота зміни не є великою.
Підходить для використання у більшості випадків. Велика кількість об’єктів в системі змінюється, але при цьому кешування об’єктів є необхідною для покращення роботи.
- nonstrict read-write – для об’єктів, що можуть змінюються в процесі роботи аплікації дуже рідко.
Кеш другого рівня дозволяє зберігати дані як в оперативній пам’яті так і на жорсткому диску. Зберігання даних на жорсткому диску актуально у випадках, коли аплікація та база даних знаходяться на різних машинах.
Коли відбувається загрузка об’єкта за допомогою Session, перш за все, Session виконує перевірку кешу на рахунок наявності в ньому об’єкту із відповідною значенням поля ідентифікації. Перевірка виконується у випадку, якщо для даного типу включено кешування другого рівня. Отже, якщо кеш містить закешований об’єкт відповідним значенням поля ідентифікації, то відбувається створення ново об’єкта у віртувальній машині та заповнення його даними.
Звідси можна зробити наступний висновок. В кеші зберігаються не об’єкти віртуальної машини, а прості дані. На основі цих даних, відбувається заповнення новоствореного об’єкту.
Якщо ж кеш не містить шуканий об’єкт, то відбувається запит до бази даних, і якщо рядок із таким ідентифікатором все-таки є в базі даних, то відбувається його поміщення в кеш. Тепер кеш містить запис для рядка із даним ідентифікатором.