FetchMode di Hibernate

1. Pengenalan

Dalam tutorial ringkas ini, kita akan melihat pelbagai nilai FetchMode yang boleh kita gunakan dalam anotasi @ org.hibernate.annotations.Fetch .

2. Menetapkan Contoh

Sebagai contoh, kami akan menggunakan entiti Pelanggan berikut dengan hanya dua sifat - satu 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 }

Juga, kami akan membuat entiti Pesanan yang terdiri daripada id, nama dan rujukan kepada 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 bahagian seterusnya, kami akan mengambil pelanggan dari pangkalan data dan mendapatkan semua pesanannya:

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

3. FetchMode.SELECT

Pada entiti Pelanggan kami , kami telah memberi anotasi pada properti pesanan dengan anotasi @Fetch :

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

Kami menggunakan @Fetch untuk menerangkan bagaimana Hibernate harus mengambil harta tanah ketika kami mencari Pelanggan.

Menggunakan SELECT menunjukkan bahawa harta tanah harus dimuat dengan malas.

Ini bermaksud bahawa untuk baris pertama:

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

Kami tidak akan melihat gabungan dengan jadual pesanan:

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

Dan itu untuk baris seterusnya:

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

Kami akan melihat pertanyaan seterusnya untuk pesanan yang berkaitan:

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

The Hibernate FetchMode.SELECT menjana pertanyaan yang berasingan bagi setiap Order yang perlu dimuatkan.

Dalam contoh kami, itu memberikan satu pertanyaan untuk memuatkan Pelanggan dan lima pertanyaan tambahan untuk memuatkan koleksi pesanan.

Ini dikenali sebagai masalah pilih n + 1. Melaksanakan satu pertanyaan akan mencetuskan n pertanyaan tambahan.

3.1. @ BatchSize

FetchMode.SELECT mempunyai anotasi konfigurasi pilihan menggunakan anotasi @BatchSize :

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

Hibernate akan cuba memuatkan koleksi pesanan dalam kumpulan yang ditentukan oleh parameter ukuran .

Dalam contoh kami, kami hanya mempunyai lima pesanan sehingga satu pertanyaan mencukupi.

Kami masih akan menggunakan pertanyaan yang sama:

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

Tetapi ia hanya akan dijalankan sekali sahaja. Sekarang kami hanya mempunyai dua pertanyaan: Satu untuk memuatkan Pelanggan dan satu untuk memuatkan koleksi pesanan.

4. FetchMode.GABUNG

Walaupun FetchMode.SELECT memuat hubungan dengan malas, FetchMode.JOIN memuatnya dengan bersemangat, katakan melalui gabung:

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

Ini menghasilkan hanya satu pertanyaan 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

Oleh kerana harta pesanan adalah koleksi, kami juga dapat menggunakan FetchMode.SUBSELECT :

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

Kami hanya boleh menggunakan SUBSELECT dengan koleksi.

Dengan penyediaan ini, kami kembali ke satu pertanyaan untuk Pelanggan:

Hibernate: select ... from customer customer0_ 

Dan satu pertanyaan untuk Pesanan , 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 subseleksi). FetchType , sebaliknya, menentukan sama ada Hibernate akan memuat data dengan bersemangat atau malas.

Peraturan yang tepat antara kedua-duanya adalah seperti berikut:

  • jika kod tidak menetapkan FetchMode , yang lalai adalah JOIN dan FetchType berfungsi seperti yang ditentukan

  • dengan FetchMode.SELECT atau FetchMode.SUBSELECT set, FetchType juga berfungsi sebagaimana yang ditakrifkan
  • dengan set FetchMode.JOIN , FetchType diabaikan dan pertanyaan sentiasa bersemangat

Untuk maklumat lebih lanjut sila rujuk Pemuatan Tidak Bersemangat / Malas Dalam Hibernate.

7. Kesimpulannya

Dalam tutorial ini, kami telah mengetahui tentang nilai-nilai FetchMode yang berbeza dan juga bagaimana ia berkaitan dengan FetchType .

Seperti biasa semua kod sumber tersedia di GitHub.