3.4.6. Кэши сущностей и запросов

Кэш сущностей (Entity Cache)

Кэш сущностей предоставляется ORM фреймворком EclipseLink. Он хранит в памяти недавно прочитанные или записанные экземпляры сущностей, тем самым сокращая доступ к базе данных и увеличивая производительность.

Кэш сущностей используется только при извлечении сущностей по идентификатору, поэтому запросы по другим атрибутам по-прежнему выполняются на базе данных. Тем не менее, эти запросы могут стать проще и быстрее, если связанные сущности находятся в кэше. Например, если вы запрашиваете Заказы вместе со связанными Заказчиками, и не используете кэш, то SQL-запрос будет содержать JOIN с таблицей заказчиков. Если же сущность Заказчик закэширована, SQL-запрос будет только по таблице заказов, а связанные заказчики будут извлечены из кэша.

Для того, чтобы включить кэш сущностей, установите следующие свойства приложения в файле app.properties модуля core вашего проекта:

  • eclipselink.cache.shared.sales$Customer = true - включает кэширование сущности sales$Customer.

  • eclipselink.cache.size.sales$Customer = 500 - устанавливает размер кэша для сущности sales$Customer в 500 экземпляров.

    Если кэширование включено, всегда рекомендуется увеличить размер кэша (по умолчанию - 100). В противном случае, если запрос вернёт более 100 записей, то каждая запись будет извлечена отдельной операцией.

Факт кэширования сущности влияет на то, какой fetch mode выбирается платформой при загрузке графов сущностей. Если некоторый ссылочный атрибут представляет собой кэшируемую сущность, то fetch mode всегда будет UNDEFINED, что позволяет ORM извлекать ссылку из кэша вместо добавления в запрос JOIN или выполнения отдельного batch-запроса.

Платформа обеспечивает координацию кэша сущностей в кластере middleware. Когда кэшированный экземпляр сущности обновляется или удаляется на одном узле кластера, тот же экземпляр на других узлах (если он загружен) будет инвалидирован, что приведет к загрузке свежего состояния из БД при следующей операции с данным экземпляром.

Кэш запросов (Query Cache)

Кэш запросов сохраняет идентификаторы экземпляров сущностей, возвращаемых JPQL-запросами, тем самым естественно дополняя кэш сущностей.

Например, если для сущности sales$Customer разрешен entity cache, и запрос select c from sales$Customer c where c.grade = :grade выполняется первый раз, происходит следующее:

  • ORM выполняет запрос в базе данных.

  • Загруженные экземпляры сущности Customer помещаются в entity cache.

  • В кэш запросов помещается соответствие между текстом запроса вместе с параметрами и списком идентификаторов загруженных экземпляров.

Когда этот же запрос с такими же параметрами выполняется второй раз, платформа находит запрос в кэше запросов и загружает экземпляры сущностей по идентификаторам из кэша сущностей, не обращаясь к базе данных.

Запросы по умолчанию не кэшируются. Указать, что запрос должен кэшироваться, можно на различных уровнях приложения:

  • Методом setCacheable() интерфейса Query при работе с EntityManager.

  • Методом setCacheable() интерфейса LoadContext.Query при работе с DataManager.

  • Методом setCacheable() интерфейса CollectionDatasource или в XML-атрибуте cacheable при работе с источниками данных.

Кэшируемые запросы следует использовать только если для возвращаемой сущности разрешен entity cache. В противном случае при каждом запросе экземпляры сущности будут загружаться из базы данных по идентификаторам по одному.

Кэш запросов автоматически инвалидируется, когда через ORM выполняются операции создания, изменения или удаления с сущностями соответствующего типа. Инвалидация работает по всему кластеру среднего слоя.

JMX-бин app-core.cuba:type=QueryCacheSupport можно использовать для мониторинга состояния кэша и для удаления запросов из кэша. Например, если вы изменили некоторый экземпляр сущности sales$Customer напрямую в БД, необходимо удалить все закэшированные запросы по этой сущности с помощью операции evict() с аргументом sales$Customer.

На поведение кэша запросов оказывают влияние следующие свойства приложения: