FetchMode no Spring Data JPA
1. Introdução
Neste breve tutorial, daremos uma olhada em diferentes valores deFetchMode que podemos usar na anotação@org.hibernate.annotations.Fetch.
2. Configurando o exemplo
Como exemplo, usaremos a seguinte entidadeCustomer com apenas duas propriedades - um id e um conjunto de pedidos:
@Entity
public class Customer {
@Id
@GeneratedValue
private Long id;
@OneToMany(mappedBy = "customer")
@Fetch(value = FetchMode.SELECT)
private Set orders = new HashSet<>();
// getters and setters
}
Além disso, criaremos uma entidadeOrder consistindo em um id, um nome e uma referência aoCustomer.
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
// getters and setters
}
Em cada uma das próximas seções, buscaremos o cliente no banco de dados e obteremos todos os seus pedidos:
Customer customer = customerRepository.findById(id).get();
Set orders = customer.getOrders();
3. FetchMode.SELECT
Em nossa entidadeCustomer, anotamos a propriedadeorders com uma anotação@Fetch:
@OneToMany
@Fetch(FetchMode.SELECT)
private Set orders;
Usamos@Fetch para descrever como o Hibernate deve recuperar a propriedade quando procuramosCustomer.
UsarSELECT indica que a propriedade deve ser carregada lentamente.
Isso significa que, para a primeira linha:
Customer customer = customerRepository.findById(id).get();
Não veremos uma junção com a tabela de pedidos:
Hibernate:
select ...from customer
where customer0_.id=?
E isso para a próxima linha:
Customer customer = customerRepository.findById(id).get();
Veremos consultas subsequentes para os pedidos relacionados:
Hibernate:
select ...from order
where order0_.customer_id=?
OHibernate FetchMode.SELECT gera uma consulta separada para cadaOrder que precisa ser carregado.
Em nosso exemplo, isso fornece uma consulta para carregar os clientes e cinco consultas adicionais para carregar a coleção de pedidos.
This is known as the n + 1 select problem. A execução de uma consulta acionarán consultas adicionais.
3.1. @BatchSize
FetchMode.SELECT tem uma anotação de configuração opcional usando a anotação@BatchSize:
@OneToMany
@Fetch(FetchMode.SELECT)
@BatchSize(size=10)
private Set orders;
Hibernate tentará carregar a coleção de pedidos em lotes definidos pelo parâmetrosize.
No nosso exemplo, temos apenas cinco pedidos, portanto, uma consulta é suficiente.
Ainda usaremos a mesma consulta:
Hibernate:
select ...from order
where order0_.customer_id=?
But it will only be run once. Agora temos apenas duas consultas: uma para carregar oCustomere outra para carregar a coleção de pedidos.
4. FetchMode.JOIN
EnquantoFetchMode.SELECT carrega relações lentamente,FetchMode.JOIN as carrega avidamente, digamos por meio de uma junção:
@OneToMany
@Fetch(FetchMode.JOIN)
private Set orders;
Isso resulta em apenas uma consulta paraCustomer e seusOrders:
Hibernate:
select ...
from
customer customer0_
left outer join
order order1
on customer.id=order.customer_id
where
customer.id=?
5. FetchMode.SUBSELECT
Como a propriedadeorders é uma coleção, também podemos usarFetchMode.SUBSELECT:
@OneToMany
@Fetch(FetchMode.SUBSELECT)
private Set orders;
Só podemos usarSUBSELECT com coleções.
Com esta configuração, voltamos a uma consulta para oCustomer:
Hibernate:
select ...
from customer customer0_
E uma consulta paraOrders, usando uma sub-seleção desta vez:
Hibernate:
select ...
from
order order0_
where
order0_.customer_id in (
select
customer0_.id
from
customer customer0_
)
6. FetchMode vs. FetchType
Em geral,FetchMode define comoHibernate buscará os dados (por seleção, junção ou subseleção). FetchType, por outro lado, define se o Hibernate carregará os dados avidamente ou lentamente.
As regras exatas entre esses dois são as seguintes:
-
[.comment-copy] #se o código não defineFetchMode, o padrão éJOINeFetchType funciona conforme definido #
-
comFetchMode.SELECT ouFetchMode.SUBSELECT definido,FetchType também funciona conforme definido
-
comFetchMode.JOIN definido,FetchType é ignorado e uma consulta está sempre ansiosa
Para obter mais informações, consulteEager/Lazy Loading In Hibernate.
7. Conclusão
Neste tutorial, aprendemos sobre os diferentes valores deFetchMode e também como eles estão relacionados aFetchType.
Como sempre, todo o código-fonte está disponível emGitHub.