FetchMode in Hibernate

1. Introduzione

In questo breve tutorial, daremo uno sguardo a diversi valori FetchMode che possiamo utilizzare nell'annotazione @ org.hibernate.annotations.Fetch .

2. Impostazione dell'esempio

Ad esempio, utilizzeremo la seguente entità Customer con solo due proprietà: un ID e un insieme di ordini:

@Entity public class Customer { @Id @GeneratedValue private Long id; @OneToMany(mappedBy = "customer") @Fetch(value = FetchMode.SELECT) private Set orders = new HashSet(); // getters and setters }

Inoltre, creeremo un'entità Ordine composta da un ID, un nome e un riferimento al Cliente .

@Entity public class Order { @Id @GeneratedValue private Long id; private String name; @ManyToOne @JoinColumn(name = "customer_id") private Customer customer; // getters and setters }

In ciascuna delle sezioni successive, recupereremo il cliente dal database e riceveremo tutti i suoi ordini:

Customer customer = customerRepository.findById(id).get(); Set orders = customer.getOrders();

3. FetchMode.SELECT

Sulla nostra entità Customer , abbiamo annotato la proprietà orders con un'annotazione @Fetch :

@OneToMany @Fetch(FetchMode.SELECT) private Set orders;

Usiamo @Fetch per descrivere come Hibernate dovrebbe recuperare la proprietà quando cerchiamo un cliente.

L'utilizzo di SELECT indica che la proprietà deve essere caricata lentamente.

Ciò significa che per la prima riga:

Customer customer = customerRepository.findById(id).get();

Non vedremo un join con la tabella degli ordini:

Hibernate: select ...from customer where customer0_.id=? 

E questo per la riga successiva:

Customer customer = customerRepository.findById(id).get();

Vedremo le query successive per gli ordini correlati:

Hibernate: select ...from order where order0_.customer_id=? 

Il Hibernate FetchMode.SELECT genera una query separata per ogni Ordine che deve essere caricato.

Nel nostro esempio, ciò fornisce una query per caricare i clienti e cinque query aggiuntive per caricare la raccolta degli ordini.

Questo è noto come problema di selezione n + 1. L'esecuzione di una query attiverà n query aggiuntive.

3.1. @ BatchSize

FetchMode.SELECT ha un'annotazione di configurazione opzionale utilizzando l' annotazione @BatchSize :

@OneToMany @Fetch(FetchMode.SELECT) @BatchSize(size=10) private Set orders;

Hibernate proverà a caricare la raccolta degli ordini in batch definiti dal parametro size .

Nel nostro esempio, abbiamo solo cinque ordini quindi una query è sufficiente.

Useremo ancora la stessa query:

Hibernate: select ...from order where order0_.customer_id=?

Ma verrà eseguito solo una volta. Ora abbiamo solo due domande: una per caricare il Cliente e una per caricare la raccolta ordini.

4. FetchMode.JOIN

Mentre FetchMode.SELECT carica pigramente le relazioni, FetchMode.JOIN le carica con entusiasmo, ad esempio tramite un join:

@OneToMany @Fetch(FetchMode.JOIN) private Set orders;

Ciò si traduce in una sola query sia per il cliente che per i suoi ordini :

Hibernate: select ... from customer customer0_ left outer join order order1 on customer.id=order.customer_id where customer.id=?

5. FetchMode.SUBSELECT

Poiché la proprietà orders è una raccolta, potremmo anche utilizzare FetchMode.SUBSELECT :

@OneToMany @Fetch(FetchMode.SUBSELECT) private Set orders;

Possiamo usare SUBSELECT solo con le raccolte.

Con questa configurazione, torniamo a una query per il cliente:

Hibernate: select ... from customer customer0_ 

E una query per gli ordini , utilizzando una sottoselezione questa volta:

Hibernate: select ... from order order0_ where order0_.customer_id in ( select customer0_.id from customer customer0_ )

6. FetchMode e FetchType

In generale, FetchMode definisce come Hibernate recupererà i dati (tramite selezione, join o sottoselezione). FetchType , d'altra parte, definisce se Hibernate caricherà i dati con impazienza o pigrizia.

Le regole esatte tra questi due sono le seguenti:

  • se il codice non imposta FetchMode , quello predefinito è JOIN e FetchType funziona come definito

  • con FetchMode.SELECT o FetchMode.SUBSELECT impostato, FetchType funziona anche come definito
  • con FetchMode.JOIN impostato, FetchType viene ignorato e una query è sempre desiderosa

Per ulteriori informazioni, fare riferimento a Caricamento desideroso / pigro in ibernazione.

7. Conclusione

In questo tutorial, abbiamo appreso i diversi valori di FetchMode e anche come sono correlati a FetchType .

Come sempre tutto il codice sorgente è disponibile su GitHub.