JPA имеет 2 уровня кэширования. Первый уровень кэширования — это постоянный контекст.
Диспетчер сущностей JPA поддерживает набор управляемых сущностей в контексте постоянства.
Entity Manager гарантирует, что в пределах одного Постоянного контекста для любой конкретной строки базы данных будет только один экземпляр объекта. Однако этим же объектом можно управлять в транзакции другого пользователя, поэтому следует использовать либо оптимистическую, либо пессимистическую блокировку, как описано в JPA 2.0 Параллелизм и блокировка
Приведенный ниже код показывает, что поиск в управляемом объекте с тем же идентификатором и классом, что и у другого в том же контексте постоянства, вернет тот же экземпляр.
@Stateless public ShoppingCartBean implements ShoppingCart {
@PersistenceContext EntityManager entityManager;
public OrderLine createOrderLine(Product product,Order order) {
OrderLine orderLine = new OrderLine(order, product);
entityManager.persist(orderLine); //Managed
OrderLine orderLine2 =entityManager.find(OrderLine,
orderLine.getId()));
(orderLine == orderLine2) // TRUE
return (orderLine);
}
}
На диаграмме ниже показан жизненный цикл сущности по отношению к постоянному контексту.
Код ниже иллюстрирует жизненный цикл сущности. Ссылка на управляемый контейнером EntityManager внедряется с использованием аннотации контекста постоянства. Новый объект заказа создается, и объект имеет состояние нового. Persist называется, делая это управляемым объектом. Поскольку это сессионный компонент без сохранения состояния, он по умолчанию использует транзакции, управляемые контейнером, когда эта транзакция фиксируется, порядок в базе данных становится постоянным. Когда сущность строки заказа возвращается в конце транзакции, это отдельная сущность.
Контекст постоянства может быть либо с областью действия транзакции — контекст постоянства «живет» на протяжении транзакции, либо с расширенным — контекст постоянства охватывает несколько транзакций. С контекстом персистентности в пределах транзакции сущности «отключаются» в конце транзакции.
Как показано ниже, чтобы сохранить изменения в отдельном объекте, вы вызываете операцию merge () EntityManager, которая возвращает обновленный управляемый объект, обновления объекта будут сохранены в базе данных в конце транзакции.
Расширенный контекст постоянства охватывает несколько транзакций, и набор сущностей в контексте постоянства остается управляемым. Это может быть полезно в сценарии рабочего процесса, когда «разговор» с пользователем охватывает несколько запросов.
Приведенный ниже код показывает пример EJB сеанса с отслеживанием состояния с расширенным контекстом постоянства в сценарии варианта использования для добавления позиций в заказ. После сохранения порядка в методе createOrder он остается управляемым до тех пор, пока не будет вызван метод удаления EJB. В методе addLineItem объект заказа можно обновить, поскольку он управляется, и обновления будут сохранены в конце транзакции.
Приведенный ниже пример контрастирует с обновлением Порядка с использованием контекста персистентности в рамках транзакции и расширенного контекста персистентности. С контекстом персистентности в области транзакций необходимо выполнить поиск Entity Manager для поиска Заказа, который возвращает управляемый объект, который можно обновить. В расширенном контексте постоянства поиск не требуется. Преимущество в производительности, заключающееся в отсутствии чтения базы данных для поиска сущности, должно быть сопоставлено с недостатками использования памяти для кэширования и риском обновления кэшированных сущностей другой транзакцией. В зависимости от приложения и риска конфликта между одновременными транзакциями это может или не может дать лучшую производительность / масштабируемость.
JPA второго уровня (L2) кэширования
Кэширование JPA второго уровня (L2) разделяет состояние объекта в различных контекстах постоянства.
В JPA 1.0 не указана поддержка кэша второго уровня, однако большинство провайдеров персистентности предоставили поддержку кэша (ов) второго уровня. В JPA 2.0 указана поддержка основных операций кеширования с новым Cache API, который доступен из EntityManagerFactory, показанного ниже:
Если кеширование L2 включено, сущности, не найденные в контексте постоянства, будут загружены из кеша L2, если они найдены.
Преимущества кэширования L2:
- избегает доступа к базе данных для уже загруженных объектов
- быстрее для чтения часто используемых неизмененных объектов
Недостатками кэширования L2 являются:
- потребление памяти для большого количества объектов
- Устаревшие данные для обновленных объектов
- Параллелизм для записи (исключение оптимистической блокировки или пессимистическая блокировка)
- Плохая масштабируемость для частых или одновременно обновляемых объектов
Вы должны настроить кэширование L2 для объектов, которые:
- читаю часто
- изменено нечасто
- Не критично, если несвежий
Вы должны защитить любые данные, которые могут быть одновременно изменены с помощью стратегии блокировки:
- Должен обрабатывать оптимистичные ошибки блокировки при сбросе / фиксации
- настроить срок действия, обновить политику, чтобы минимизировать ошибки блокировки
Кэш запросов полезен для запросов, которые часто выполняются с одинаковыми параметрами, для неизмененных таблиц.
Архитектура кэширования поставщика сохраняемости EclipseLink JPA
Архитектура кэширования EclipseLink показана ниже.
Поддержка кеша второго уровня в EclipseLink включена по умолчанию, читаемые объекты кэшируются на уровне L2. Вы можете отключить кэш L2. EclipseLink кэширует объекты в L2, Hibernate кэширует идентификатор и состояние объектов в L2. Вы можете настроить кэширование по типу сущности или единице постоянства со следующими параметрами конфигурации:
- Изоляция кэша, тип, размер, срок действия, координация, аннулирование, обновление
- Координация (кластер-обмен сообщениями)
- Обмен сообщениями: JMS, RMI, RMI-IIOP,…
- Режим: SYNC, SYNC + NEW, INVALIDATE, NONE
В приведенном ниже примере показано, как настроить кэш L2 для объекта с помощью аннотации @Cache.
Архитектура кэширования провайдера Hibernate JPA
Архитектура кэширования провайдера Hibernate JPA отличается от EclipseLink: она не настроена по умолчанию, она не кэширует объекты, а только id и состояние, и вы можете подключать разные кэши L2. На приведенной ниже схеме показаны различные типы кэша L2, которые вы можете подключить к Hibernate.
Конфигурация кэша зависит от типа подключенного кэширования. В приведенном ниже примере показано, как настроить кэш L2 в спящем режиме для объекта с помощью аннотации @Cache.
За дополнительной информацией:
EclipseLink JPA Руководство пользователя
Кэширование второго уровня в Hibernate Ускорьте
свои приложения Hibernate с помощью кэширования второго уровня Кэширование в
Java Persistence API 2.0: что нового
Начало платформы Java ™ EE 6 с GlassFish ™ 3
Pro EJB 3: API персистентности Java (JPA 1.0)