FetchMode dalam mode Hibernate

1. Perkenalan

Dalam tutorial singkat ini, kita akan melihat nilai FetchMode berbeda yang dapat kita gunakan di anotasi @ org.hibernate.annotations.Fetch .

2. Menyiapkan Contoh

Sebagai contoh, kami akan menggunakan entitas Pelanggan berikut hanya dengan dua properti - id dan satu set pesanan:

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

Selain itu, kami akan membuat entitas Pesanan yang terdiri dari id, nama, dan referensi ke Pelanggan .

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

Di setiap bagian berikutnya, kita akan mengambil pelanggan dari database dan mendapatkan semua pesanannya:

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

3. FetchMode.SELECT

Di entitas Pelanggan kami , kami telah menganotasi properti pesanan dengan anotasi @Fetch :

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

Kami menggunakan @Fetch untuk menjelaskan bagaimana Hibernate harus mengambil properti saat kami mencari Pelanggan.

Menggunakan SELECT menunjukkan bahwa properti harus dimuat dengan lambat.

Artinya untuk baris pertama:

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

Kami tidak akan melihat bergabung dengan tabel pesanan:

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

Dan untuk baris berikutnya:

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

Kami akan melihat kueri berikutnya untuk pesanan terkait:

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

The Hibernate FetchMode.SELECT menghasilkan query terpisah untuk setiap Orde yang perlu dimuat.

Dalam contoh kami, itu memberikan satu kueri untuk memuat Pelanggan dan lima kueri tambahan untuk memuat kumpulan pesanan.

Ini dikenal sebagai masalah pemilihan n + 1. Menjalankan satu kueri akan memicu n kueri tambahan.

3.1. @ Batchize

FetchMode.SELECT memiliki anotasi konfigurasi opsional menggunakan anotasi @BatchSize :

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

Hibernate akan mencoba memuat kumpulan pesanan dalam batch yang ditentukan oleh parameter ukuran .

Dalam contoh kami, kami hanya memiliki lima pesanan sehingga satu kueri sudah cukup.

Kami masih akan menggunakan kueri yang sama:

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

Tapi itu hanya akan dijalankan sekali. Sekarang kita hanya memiliki dua kueri: Satu untuk memuat Pelanggan dan satu lagi untuk memuat koleksi pesanan.

4. FetchMode.JOIN

Saat FetchMode.SELECT memuat relasi dengan malas, FetchMode.JOIN memuatnya dengan penuh semangat, katakan melalui join:

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

Ini menghasilkan hanya satu kueri untuk Pelanggan dan Pesanan mereka :

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

5. FetchMode.SUBSELECT

Karena properti pesanan adalah kumpulan, kita juga bisa menggunakan FetchMode.SUBSELECT :

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

Kami hanya dapat menggunakan SUBSELECT dengan koleksi.

Dengan penyiapan ini, kita kembali ke satu kueri untuk Pelanggan:

Hibernate: select ... from customer customer0_ 

Dan satu kueri untuk Order s, menggunakan sub-pilih kali ini:

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

6. FetchMode vs. FetchType

Secara umum, FetchMode menentukan bagaimana Hibernate akan mengambil data (dengan memilih, bergabung atau subpilih). FetchType , di sisi lain, menentukan apakah Hibernate akan memuat data dengan bersemangat atau malas.

Aturan persis di antara keduanya adalah sebagai berikut:

  • jika kode tidak menyetel FetchMode , yang default adalah JOIN dan FetchType berfungsi seperti yang ditentukan

  • dengan FetchMode.SELECT atau FetchMode.SUBSELECT set, FetchType juga bekerja seperti yang didefinisikan
  • dengan set FetchMode.JOIN , FetchType diabaikan dan kueri selalu bersemangat

Untuk informasi lebih lanjut, silakan merujuk ke Eager / Lazy Loading In Hibernate.

7. Kesimpulan

Dalam tutorial ini, kita telah belajar tentang nilai FetchMode yang berbeda dan juga bagaimana mereka terkait dengan FetchType .

Seperti biasa, semua kode sumber tersedia di GitHub.