ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 01.12.2023

Просмотров: 417

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Hibernate не реализует сам никакого in-memory сache, а использует существующие реализации кешей.
Как работать с кешем 2 уровня?
Чтение из кеша второго уровня происходит только в том случае, если нужный объект не был найден в кеше первого уровня.
Hibernate поставляется со встроенной поддержкой стандарта кеширования Java JCache, а также двух популярных библиотек кеширования: Ehcache и Infinispan.
В Hibernate кеширование второго уровня реализовано в виде абстракции, то есть необходимо предоставить любую ее реализацию. Например, можно использовать следующих провайдеров: Ehcache, OSCache, SwarmCache, JBoss TreeCache. Для Hibernate требуется только реализация интерфейса org.hibernate.cache.spi.RegionFactory, который инкапсулирует все детали, относящиеся к конкретным провайдерам. По сути RegionFactory действует как мост между Hibernate и поставщиками кеша. В качестве примера воспользуемся Ehcache. Для этого:

добавим мавен-зависимость кеш-провайдера нужной версии;

включим кеш второго уровня и определить конкретного провайдера;
hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory

установим у нужных сущностей JPA-аннотацию @Cacheable, обозначающую, что сущность нужно кешировать, и Hibernate-аннотацию @Cache, настраивающую детали кеширования, у которой в качестве параметра указать стратегию параллельного доступа.
Стратегии параллельного доступа к объектам:
Проблема заключается в том, что кеш второго уровня доступен из нескольких сессий сразу и несколько потоков программы могут одновременно в разных транзакциях работать с одним и тем же объектом. Следовательно надо как-то обеспечивать их одинаковым представлением этого объекта.

1   ...   17   18   19   20   21   22   23   24   25

READ_ONLY: Используется только для сущностей, которые никогда не изменяются
(будет выброшено исключение, если попытаться обновить такую сущность). Просто и производительно. Подходит для некоторых статических данных, которые не меняются.

NONSTRICT_READ_WRITE: Кеш обновляется после совершения транзакции, которая изменила данные в БД и закоммитила их. Таким образом, строгая согласованность не гарантируется, и существует небольшое временное окно между обновлением данных в БД и обновлением тех же данных в кеше, во время которого параллельная транзакция может получить из кеша устаревшие данные.

READ_WRITE: Гарантирует строгую согласованность, которая достигается за счет
«мягких» блокировок: когда обновляется кешированная сущность, на нее накладывается мягкая блокировка, которая снимается после коммита транзакции. Все параллельные транзакции, которые пытаются получить доступ к записям в кеше с наложенной мягкой блокировкой, не смогут их прочитать или записать и отправят запрос в БД. Ehcache использует эту стратегию по умолчанию.


TRANSACTIONAL: полноценное разделение транзакций. Каждая сессия и каждая транзакция видят объекты, словно они работали с ними последовательно одна транзакция за другой. Плата за это – блокировки и потеря производительности.
Что такое JPQL/HQL и чем он отличается от SQL?
Hibernate Query Language (HQL) и Java Persistence Query Language (JPQL) являются объектно-ориентированными языками запросов, схожими по природе с SQL. JPQL – это подмножество HQL.
JPQL – это язык запросов, практически такой же, как SQL, но вместо имен и колонок таблиц базы данных использует имена классов Entity и их атрибуты. В качестве параметров запросов используются типы данных атрибутов Entity, а не полей баз данных. В отличие от
SQL в JPQL есть автоматический полиморфизм, то есть каждый запрос к Entity возвращает не только объекты этого Entity, но и объекты всех его классов-потомков, независимо от стратегии наследования. В JPA запрос представлен в виде javax.persistence.Query или javax.persistence.TypedQuery, полученных из EntityManager.
В Hibernate HQL-запрос представлен org.hibernate.query.Query, полученный из Session. Если
HQL является именованным запросом, то будет использоваться Session#getNamedQuery, в противном случае требуется Session#createQuery.
Что такое Criteria API и для чего он используется?
Начиная с версии 5.2, Hibernate Criteria API объявлен deprecated. Вместо него рекомендуется использовать JPA Criteria API.
JPA Criteria API – это актуальный API, используемый только для выборки (select) сущностей из БД в более объектно-ориентированном стиле.
Основные преимущества JPA Criteria API:

ошибки могут быть обнаружены во время компиляции;

позволяет динамически формировать запросы на этапе выполнения приложения.
Основные недостатки:

нет контроля над запросом, сложно отловить ошибку;

влияет на производительность, множество классов.
Для динамических запросов фрагменты кода создаются во время выполнения, поэтому JPA
Criteria API является предпочтительней.
Н
екоторые области применения Criteria API:

поддерживает проекцию, которую можно использовать для агрегатных функций вроде sum(), min(), max() и т. д.;

может использовать ProjectionList для извлечения данных только из выбранных колонок;

может быть использована для join запросов с помощью соединения нескольких таблиц, используя методы createAlias(), setFetchMode() и setProjection();

поддерживает выборку результатов согласно условиям (ограничениям). Для этого используется метод add(), с помощью которого добавляются ограничения
(Restrictions).



позволяет добавлять порядок (сортировку) к результату с помощью метода addOrder().
Расскажите про проблему N+1 Select и путях ее решения
Проблема N+1 запросов возникает, когда получение данных из БД выполняется за N
дополнительных SQL-запросов для извлечения тех же данных, которые могли быть получены при выполнении основного SQL-запроса.
1. JOIN FETCH
И при FetchType.EAGER, и при FetchType.LAZY поможет JPQL-запрос с JOIN FETCH. Опцию
«FETCH» можно использовать в JOIN (INNER JOIN или LEFT JOIN) для выборки связанных объектов в одном запросе вместо дополнительных запросов для каждого доступа к ленивым полям объекта.
Лучший вариант решения для простых запросов (1-3 уровня вложенности связанных объектов).
select pc
from PostComment pc
join fetch pc.post p
2. EntityGraph
Если нужно получить много данных через jpql-запрос, лучше всего использовать EntityGraph.
3. @Fetch(FetchMode.SUBSELECT)
Аннотация Hibernate. Можно использовать только с коллекциями. Будет сделан один sql- запрос для получения корневых сущностей и, если в контексте персистентности будет обращение к ленивым полям-коллекциям, то выполнится еще один запрос для получения связанных коллекций:
@Fetch(value = FetchMode.SUBSELECT)
private Set orders = new HashSet<>();
4. Batch fetching
Аннотация Hibernate, в JPA ее нет. Указывается над классом сущности или над полем коллекции с ленивой загрузкой. Будет сделан один sql-запрос для получения корневых сущностей и, если в контексте персистентности будет обращение к ленивым полям- коллекциям, то выполнится еще один запрос для получения связанных коллекций.
Количество загружаемых сущностей указывается в аннотации.
@BatchSize(size=5)
private Set orders = new HashSet<>();
5. HibernateSpecificMapping, SqlResultSetMapping
Рекомендуется использовать для нативных запросов.
Что такое EntityGraph? Как и для чего их использовать?
Основная цель JPA Entity Graph – улучшить производительность в рантайме при загрузке базовых полей сущности и связанных сущностей и коллекций.

Hibernate загружает весь граф в одном SELECT-запросе, то есть все указанные связи от нужной сущности. Если необходимо загрузить дополнительные сущности, находящиеся в связанных сущностях, используется Subgraph.
EntityGraph можно определить с помощью аннотации @NamedEntityGraph для Entity, она определяет уникальное имя и список атрибутов (attributeNodes), которые должны быть загружены с использованеим entityManager из JPA API:
EntityGraph entityGraph = entityManager.createEntityGraph(Post.class);
entityGraph.addAttributeNodes("subject");
entityGraph.addAttributeNodes("user");
entityGraph.addSubgraph("comments").addAttributeNodes("user");
JPA определяет два свойства или подсказки, с помощью которых Hibernate может выбирать стратегию извлечения графа сущностей во время выполнения:

fetchgraph – все атрибуты, перечисленные в EntityGraph, меняют fetchType на
EAGER, все остальные – на LAZY;

loadgraph – все атрибуты, перечисленные в EntityGraph, меняют fetchType на EAGER,
все остальные сохраняют свой fetchType. С помощью NamedSubgraph можно изменить fetchType вложенных объектов Entity.
Загрузить EntityGraph можно тремя способами:
1. Используя перегруженный метод find(), который принимает Map с настройками
EntityGraph.
2. Используя JPQL и передав подсказку через setHint().
3. С помощью Criteria API.
Мемоизация
Memoization – вариант кеширования, заключающийся в том, что для функции создается таблица результатов. Результат функции, вычисленной при определенных значениях параметров, заносится в эту таблицу. В дальнейшем результат берется из данной таблицы.
Эта техника позволяет за счет использования дополнительной памяти ускорить работу программы.
Можно применить только к функциям, которые являются:

детерминированными (т. е. при одном и том же наборе параметров функции должны возвращать одинаковое значение);

без побочных эффектов (т. е. не должны влиять на состояние системы).
В Java наиболее подходящей кандидатурой на роль хранилища является интерфейс Map.
Сложность операций get,put,contains равна O(1). Это позволяет гарантировать ограничение задержки при выполнении мемоизации.
Мемоизация реализована в библиотеке ehcache.


Spring
Что такое инверсия контроля (IoC) и внедрение зависимостей (DI)? Как эти
принципы реализованы в Spring?
Inversion of Control – подход, который позволяет конфигурировать и управлять объектами
Java с помощью рефлексии. Вместо ручного внедрения зависимостей фреймворк забирает ответственность за это через IoC-контейнер. Контейнер отвечает за управление жизненным циклом объектов: создание объектов, вызов методов инициализации и конфигурирование объектов через связывание их между собой.
Объекты, создаваемые контейнером, называются beans. Конфигурирование контейнера осуществляется через внедрение аннотаций, но есть возможность, по старинке, загрузить
XML-файлы, содержащие определение bean’ов и предоставляющие информацию,
необходимую для создания bean’ов.
Dependency Injection является одним из способов реализации принципа IoC в Spring. Это шаблон проектирования, в котором контейнер передает экземпляры объектов по их типу другим объектам с помощью конструктора или метода класса (setter), что позволяет писать слабосвязный код.
Что такое IoC контейнер?
В среде Spring IoC-контейнер представлен интерфейсом ApplicationContext, который является оберткой над BeanFactory, предоставляющей дополнительные возможности,
например AOP и транзакции. Интерфейс BeanFactory предоставляет фабрику для бинов,
которая в то же время является IoC-контейнером приложения. Управление бинами основано на конфигурации (аннотации или xml). Контейнер создает объекты на основе конфигураций и управляет их жизненным циклом от создания объекта до уничтожения.
Расскажите про ApplicationContext и BeanFactory, чем отличаются? В каких
случаях что стоит использовать?
ApplicationContext является наследником BeanFactory и полностью реализует его функционал, добавляя больше специфических enterprise-функций. Может работать с бинами всех скоупов.
BeanFactory – это фактический контейнер, который создает, настраивает и управляет рядом bean-компонентов. Эти бины обычно взаимодействуют друг с другом и имеют зависимости между собой. Эти зависимости отражены в данных конфигурации, используемых
BeanFactory. Может работать с бинами singleton и prototype.


BeanFactory обычно используется тогда, когда ресурсы ограничены (мобильные устройства),
так как он легче по сравнению с ApplicationContext. Поэтому, если ресурсы не сильно ограничены, то лучше использовать ApplicationContext.
ApplicationContext загружает все бины при запуске, а BeanFactory по требованию.
Расскажите про аннотацию @Bean?
Аннотация @Bean используется для указания того, что метод создает, настраивает и инициализирует новый объект, управляемый IoC-контейнером. Такие методы можно использовать как в классах с аннотацией @Configuration, так и в классах с аннотацией
@Component (или ее наследниках).
Имеет следующие свойства:

destroyMethod, initMethod – варианты переопределения методов инициализации и удаления бина при указании их имен в аннотации;

name – имя бина, по умолчанию именем бина является имя метода;

value – алиас для name().
Расскажите про аннотацию @Component?
@Component используется для указания класса в качестве компонента Spring. Такой класс будет сконфигурирован как spring Bean.
Чем отличаются аннотации @Bean и @Component?
@Bean ставится над методом и позволяет добавить bean, уже реализованного сторонней библиотекой класса, в контейнер, а @Component используется для указания класса,
написанного программистом.
Расскажите про аннотации @Service и @Repository. Чем они отличаются?
@Repository указывает, что класс используется для работы с поиском, получением и хранением данных. Аннотация может использоваться для реализации шаблона DАО.
@Service указывает, что класс является сервисом для реализации бизнес-логики.
@Repository, @Service, @Controller и @Configuration являются алиасами @Component, их также называют стереотипными аннотациями.
Задача @Repository заключается в том, чтобы отлавливать определенные исключения персистентности и пробрасывать их как одно непроверенное исключение Spring Framework.
Для этого в
контекст должен быть добавлен класс
PersistenceExceptionTranslationPostProcessor.
Расскажите про аннотацию @Autowired
@Autowired – автоматическое внедрение подходящего бина:
1. Контейнер определяет тип объекта для внедрения.
2. Контейнер ищет соответствующий тип бина в контексте (он же контейнер).
3. Если есть несколько кандидатов и один из них помечен как @Primary, то внедряется он.