До выхода версии JPA 2.0 в спецификации кэширование не упоминалось. Менеджер сущностей является кэшем первого уровня, используемым для всесторонней обработки информации для базы данных, а также для кэширования сущностей, которые живут короткий период времени. Этот кэш первого уровня задействуется отдельно в случае с каждой транзакцией для уменьшения количества SQL-запросов в рамках определенной транзакции. Например, если объект будет модифицирован несколько раз в рамках одной и той же транзакции, то менеджер сущностей сгенерирует только один оператор UPDATE в конце этой транзакции. Кэш первого уровня не является производительным кэшем.

Однако все реализации JPA используют производительный кэш (также называемый кэшем второго уровня) для оптимизации доступа к базам данных, запросов, соединений и т. д. Как показано на рис. 6.3, кэш второго уровня располагается между менеджером сущностей и базой данных с целью уменьшения трафика путем сохранения объектов загруженными в память и доступными для всего приложения.

Рис. 6.3. Кэш второго уровня

Каждая реализация наделяется своим подходом к кэшированию объектов путем либо разработки собственного механизма, либо повторного использования уже существующих решений (с открытым исходным кодом или коммерческих). Кэширование может быть распределено по кластеру либо нет — все возможно, когда спецификация игнорирует соответствующую тему. Создатели JPA 2.0 признали, что кэш второго уровня необходим, и добавили операции кэширования в стандартный API-интерфейс. Приведенный в листинге 6.33 API-интерфейс крайне минималистичен (поскольку цель JPA не заключается в том, чтобы стандартизировать полнофункциональный кэш), однако позволяет коду выполнять запросы к некоторым сущностям и удалять их из кэша второго уровня стандартным образом. Как и менеджер сущностей, javax.persistence.Cache является интерфейсом, реализуемым системой кэширования поставщика постоянства.

Листинг 6.33. Cache API

public interface Cache {

··// Содержит ли кэш определенную сущность

··public boolean contains(Class cls, Object id);

··// Удаляет сущность из кэша

··public void evict(Class cls, Object id);

··// Удаляет сущности указанного класса (и его подклассы) из кэша

··public void evict(Class cls);

··// Очищает кэш

··public void evictAll();

··// Возвращает реализацию кэша, специфичную для поставщика

··public  T unwrap(Class cls);

}

Вы можете использовать этот API для проверки того, содержится ли определенная сущность в кэше второго уровня, а также для очищения всего кэша. Задействуя этот API, вы можете явным образом проинформировать поставщика постоянства о том, является ли сущность кэшируемой, с помощью аннотации @Cacheable, как показано в листинге 6.34. Если у сущности отсутствует аннотация @Cacheable, то эта сущность и ее состояние не должны кэшироваться поставщиком.

Листинг 6.34. Сущность Customer является кэшируемой

@Entity

@Cacheable(true)

public class Customer {

··@Id @GeneratedValue

··private Long id;

··private String firstName;

··private String lastName;

··private String email;

··// Конструкторы, геттеры, сеттеры

}

Аннотация @Cacheable принимает логическое значение. Как только вы решите, какая сущность должна быть кэшируемой, вам придется проинформировать поставщика о том, какой механизм кэширования следует использовать. Это можно сделать с помощью JPA, указав атрибут shared-cache-mode в файле persistence.xml. Далее приведены возможные значения:

• ALL — будут кэшироваться все сущности, а также связанные с ними состояния и данные;

• DISABLE_SELECTIVE — будут кэшироваться все сущности за исключением тех, что снабжены аннотацией @Cacheable(false);

• ENABLE_SELECTIVE — будут кэшироваться все сущности, снабженные аннотацией @Cacheable(true);

• NONE — кэширование будет отключено для единицы сохраняемости;

• UNSPECIFIED — поведение кэширования будет неопределенным (могут быть применены правила по умолчанию, специфичные для поставщика).

Перейти на страницу:

Похожие книги