Выполняет ли OneToMany (fetch = FetchType.EAGER) N + 1 запрос - PullRequest
0 голосов
/ 27 декабря 2018

Я разрабатываю приложение, используя Spring Boot, Spring Data и Hibernate.У меня есть сущность «Клиент», которая имеет отношение «онтомания» с другой сущностью «Резервирование» следующим образом:

@Entity
public class Client implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany( mappedBy = "client", fetch=FetchType.EAGER)
    @Fetch(value = FetchMode.JOIN)
    private Set<Reservation> reservations = new HashSet<>();
}

Я реализовал интерфейс JpaRepository, чтобы я мог манипулировать данными клиента:

public interface ClientRepository extends JpaRepository<Client, Long> {}

В классе обслуживания я реализовал метод поиска всех клиентов в моей базе данных:

@Service
public class ClientService {

@Autowired
private ClientRepository clientRepository;

@Transactional(readOnly = true)
public List<Client> findAll() {

    return clientRepository.findAll();
}}

Выполнение findAll () работает хорошо и возвращает всех клиентов и их резервирование.Тем не менее, в моем журнале sql у меня есть N + 1 запросов, которые были выполнены (N количество клиентов), хотя я установил fetch=FetchType.EAGER в моем объекте Client.Я думал, что hibernate создаст один запрос, в котором он объединит все необходимые данные для получения клиентов и их повторных запросов.

Итак, я вынужден явно присоединиться к клиенту и выполнить резервирование с помощью запроса:

    @Query("select client from Client client left join fetch client.reservations")
public List<Client> findAllEager();

Я также нашел другую альтернативу, которая позволяет выполнять только два запроса для извлечения всех клиентов и их резервирований:

    @OneToMany(mappedBy = "client", fetch = FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)

Я отмечаю, что из этого обсуждения JPA eager fetch не присоединяется, похоже, что @OneToMany(fetch=FetchType.EAGER) @Fetch(value = FetchMode.JOIN) выполнит только один запрос для получения результата, который не является моим случаем.

Выполняет ли OneToMany(fetch=FetchType.EAGER) N + 1 запрос для извлечения данных?

1 Ответ

0 голосов
/ 27 декабря 2018

@OneToMany(fetch=FetchType.EAGER) определяет только когда связанные объекты выбираются, но не определяет как объекты выбираются.(то есть, выбираются ли они одним объединенным SQL или множеством разделенных SQL), поэтому он может выполнить N + 1 запросов.

@Fetch(value = FetchMode.JOIN) определяет способ выборки связанных объектов. Однако он работает только тогда, когда объекты выбираются напрямую с использованием идентификатора (т. Е. Через entityManager.find(Client.class, 100)), но не будет влиять на запрос JPQL или Criteria API.пользователем Hibernate, как ниже ):

Причина, по которой мы не используем запрос JPQL для выборки нескольких объектов Department, заключается в том, что стратегия FetchMode.JOIN будет переопределенадиректива выборки запроса.

Чтобы извлечь несколько отношений с помощью запроса JPQL, вместо этого должна использоваться директива JOIN FETCH.

Поэтому FetchMode.JOIN полезен для случаев, когда сущности выбираются напрямую через ихидентификатор или натуральный идентификатор.

Данные Spring внутренне используют Criteria API для запроса findAll(), поэтому @Fetch(value = FetchMode.JOIN) не будет иметь никакого эффекта. Вы должны явно использовать запрос JOIN FETCH, чтобы избежатьN + 1 запросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...