Apa sebenarnya yang dikontrol strategi pengambilan JPA? Saya tidak dapat mendeteksi perbedaan apa pun antara bersemangat dan malas. Dalam kedua kasus JPA / Hibernate tidak secara otomatis menggabungkan hubungan banyak-ke-satu.
Contoh: Orang memiliki satu alamat. Sebuah alamat bisa menjadi milik banyak orang. Kelas entitas beranotasi JPA terlihat seperti:
@Entity
public class Person {
@Id
public Integer id;
public String name;
@ManyToOne(fetch=FetchType.LAZY or EAGER)
public Address address;
}
@Entity
public class Address {
@Id
public Integer id;
public String name;
}
Jika saya menggunakan kueri JPA:
select p from Person p where ...
JPA / Hibernate menghasilkan satu kueri SQL untuk dipilih dari tabel Orang, dan kemudian kueri alamat berbeda untuk setiap orang:
select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3
Ini sangat buruk untuk set hasil yang besar. Jika ada 1000 orang, itu menghasilkan 1001 kueri (1 dari Orang dan 1000 berbeda dari Alamat). Saya tahu ini karena saya melihat log kueri MySQL. Itu adalah pemahaman saya bahwa pengaturan tipe fetch alamat menjadi bersemangat akan menyebabkan JPA / Hibernate secara otomatis melakukan kueri dengan bergabung. Namun, apa pun jenis pengambilannya, ini tetap menghasilkan kueri yang berbeda untuk hubungan.
Hanya ketika saya secara eksplisit menyuruhnya untuk bergabung, apakah itu benar-benar bergabung:
select p, a from Person p left join p.address a where ...
Apakah saya melewatkan sesuatu di sini? Saya sekarang harus memberikan kode untuk setiap kueri sehingga meninggalkan hubungan banyak-ke-satu. Saya menggunakan implementasi JPA Hibernate dengan MySQL.
Sunting: Tampaknya (lihat FAQ Hibernasi di sini dan di sini ) yang FetchType
tidak memengaruhi kueri JPA. Jadi dalam kasus saya, saya secara eksplisit menyuruhnya bergabung.
Jawaban:
JPA tidak memberikan spesifikasi apa pun tentang anotasi pemetaan untuk memilih strategi pengambilan. Secara umum, entitas terkait dapat diambil dengan salah satu cara yang diberikan di bawah ini
Jadi
SELECT
danJOIN
adalah dua ekstrem danSUBSELECT
berada di antara keduanya. Seseorang dapat memilih strategi yang sesuai berdasarkan model domainnya.Secara default
SELECT
digunakan oleh JPA / EclipseLink dan Hibernate. Ini dapat diganti dengan menggunakan:dalam mode Hibernate. Ini juga memungkinkan untuk mengatur
SELECT
mode secara eksplisit@Fetch(FetchMode.SELECT)
yang dapat disetel dengan menggunakan ukuran batch misalnya@BatchSize(size=10)
.Anotasi terkait di EclipseLink adalah:
sumber
"mxc" benar.
fetchType
hanya menentukan kapan relasi harus diselesaikan.Untuk mengoptimalkan eager loading dengan menggunakan gabungan luar, Anda harus menambahkan
ke bidang Anda. Ini adalah anotasi khusus hibernasi.
sumber
Atribut fetchType mengontrol apakah kolom beranotasi diambil segera saat entitas utama diambil. Itu tidak selalu menentukan bagaimana pernyataan fetch dibangun, implementasi sql sebenarnya tergantung pada penyedia yang Anda gunakan toplink / hibernate dll.
Jika Anda mengatur
fetchType=EAGER
Ini berarti bahwa bidang beranotasi diisi dengan nilainya pada saat yang sama dengan bidang lain di entitas. Jadi, jika Anda membuka pengelola entitas, ambil objek person Anda dan kemudian tutup pengelola entitas, selanjutnya melakukan person.address tidak akan mengakibatkan pengecualian pemuatan lambat dilemparkan.Jika Anda mengatur
fetchType=LAZY
bidang hanya diisi saat diakses. Jika Anda telah menutup entitymanager saat itu, pengecualian lazy load akan muncul jika Anda melakukan person.address. Untuk memuat bidang, Anda perlu meletakkan entitas kembali ke konteks entitasmangers dengan em.merge (), lalu lakukan akses bidang dan kemudian tutup manajer entitas.Anda mungkin ingin pemuatan lambat saat membuat kelas pelanggan dengan koleksi untuk pesanan pelanggan. Jika Anda mengambil setiap pesanan untuk pelanggan saat Anda ingin mendapatkan daftar pelanggan, ini mungkin operasi database yang mahal saat Anda hanya mencari nama pelanggan dan detail kontak. Sebaiknya tinggalkan akses db sampai nanti.
Untuk bagian kedua dari pertanyaan - bagaimana mendapatkan hibernate untuk menghasilkan SQL yang dioptimalkan?
Hibernate memungkinkan Anda memberikan petunjuk tentang cara membuat kueri yang paling efisien, tetapi saya curiga ada yang salah dengan konstruksi tabel Anda. Apakah hubungan ditetapkan dalam tabel? Hibernate mungkin telah memutuskan bahwa kueri sederhana akan lebih cepat daripada bergabung terutama jika indeks dll hilang.
sumber
Coba dengan:
Ini berfungsi untuk saya serupa dengan JPA2 / EclipseLink, tetapi tampaknya fitur ini juga ada di JPA1 :
sumber
Jika Anda menggunakan EclipseLink dan bukan Hibernate, Anda dapat mengoptimalkan kueri Anda dengan "petunjuk permintaan". Lihat artikel ini dari Eclipse Wiki: EclipseLink / Example / JPA / QueryOptimization .
Ada bab tentang "Membaca Bersama".
sumber
untuk bergabung kamu bisa melakukan banyak hal (menggunakan eclipselink)
di jpql Anda bisa melakukan left join fetch
dalam kueri bernama Anda dapat menentukan petunjuk kueri
di TypedQuery, Anda bisa mengatakan sesuatu seperti
query.setHint("eclipselink.join-fetch", "e.projects.milestones");
ada juga petunjuk pengambilan batch
query.setHint("eclipselink.batch", "e.address");
Lihat
http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html
sumber
Saya memiliki masalah ini dengan pengecualian bahwa kelas Person memiliki kelas kunci yang disematkan. Solusi saya sendiri adalah bergabung dengan mereka dalam kueri DAN hapus
@Fetch(FetchMode.JOIN)
Kelas id saya yang disematkan:
sumber
Dua hal terjadi pada saya.
Pertama, apakah Anda yakin yang Anda maksud ManyToOne untuk alamat? Artinya, beberapa orang akan memiliki alamat yang sama. Jika diedit untuk salah satu dari mereka, itu akan diedit untuk semuanya. Apa itu maksudmu? 99% alamat waktu bersifat "pribadi" (dalam arti bahwa alamat tersebut hanya dimiliki oleh satu orang).
Kedua, apakah Anda memiliki hubungan bersemangat lainnya di entitas Person? Jika saya ingat dengan benar, Hibernate hanya dapat menangani satu hubungan yang bersemangat pada suatu entitas tetapi itu mungkin informasi yang sudah ketinggalan zaman.
Saya mengatakan itu karena pemahaman Anda tentang bagaimana ini seharusnya bekerja pada dasarnya benar dari tempat saya duduk.
sumber