Hibernate: Perbedaan antara session.get dan session.load

88

Dari API, saya bisa melihat itu ada hubungannya dengan proxy. Tetapi saya tidak dapat menemukan banyak informasi tentang proxy dan tidak memahami perbedaan antara menelepon session.getdan session.load. Bisakah seseorang menjelaskan atau mengarahkan saya ke halaman referensi?

Terima kasih!!

tomat
sumber

Jawaban:

117

Dari forum Hibernate :

Ini dari buku Hibernate in Action. Bagus membaca ini ..


Mengambil objek dengan pengidentifikasi Potongan kode Hibernate berikut mengambil objek pengguna dari database:

User user = (User) session.get(User.class, userID);

Metode get () adalah khusus karena pengenal secara unik mengidentifikasi satu instance kelas. Oleh karena itu, aplikasi umum untuk menggunakan pengenal sebagai pegangan yang nyaman untuk objek yang persisten. Pengambilan dengan pengenal bisa menggunakan cache saat mengambil objek, menghindari database yang terkena jika objek sudah di-cache. Hibernate juga menyediakan metode load ():

User user = (User) session.load(User.class, userID);

Metode load () lebih lama; get () ditambahkan ke API Hibernate karena permintaan pengguna. Perbedaannya sepele:

Jika load () tidak dapat menemukan objek dalam cache atau database, pengecualian akan dilemparkan. Metode load () tidak pernah mengembalikan nol. Metode get () mengembalikan null jika objek tidak dapat ditemukan.

Metode load () mungkin mengembalikan proxy alih-alih instance persisten yang nyata. Proksi adalah placeholder yang memicu pemuatan objek nyata saat diakses pertama kali; Di sisi lain, get () tidak pernah mengembalikan proxy. Memilih antara get () dan load () itu mudah: Jika Anda yakin objek persisten ada, dan tidak ada akan dianggap luar biasa, load () adalah pilihan yang baik. Jika Anda tidak yakin ada instance persisten dengan pengenal yang diberikan, gunakan get () dan uji nilai yang dikembalikan untuk melihat apakah nilainya null. Menggunakan load () memiliki implikasi lebih lanjut: Aplikasi dapat mengambil referensi yang valid (proxy) ke instance persisten tanpa menyentuh database untuk mengambil status persistennya. Jadi, load () mungkin tidak memunculkan pengecualian jika tidak menemukan objek persisten dalam cache atau database; pengecualian akan dilempar nanti, saat proxy diakses. Tentu saja, mengambil objek dengan pengenal tidak sefleksibel menggunakan kueri arbitrer.

duffymo
sumber
1
Saya sedang men-debug masalah saat ini di mana session.Get <T> () mengembalikan proxy!
Kent Boogaart
7
Terima kasih banyak! Bagian uang bagi saya adalah: "Jika load () tidak dapat menemukan objek dalam cache atau database, pengecualian dilemparkan. Metode get () mengembalikan null jika objek tidak dapat ditemukan."
Chris
15
JavaDoc untuk Session.get mengatakan: Kembalikan instance persisten dari kelas entitas yang diberikan dengan pengenal yang diberikan, atau null jika tidak ada instance persisten seperti itu. (Jika instance, atau proxy untuk instance, sudah dikaitkan dengan sesi, kembalikan instance atau proxy itu.) Jadi bagian dari buku yang mengatakan: "Di sisi lain, get () tidak pernah mengembalikan proxy." tidak benar.
Vicky
jika Anda menggunakan strategi manajemen transaksi dengan daos Anda, Anda mungkin lebih memilih get (). jika tidak, pemanggil juga harus menjalankan dalam konteks sesi hibernasi terbuka jika load () mengembalikan proxy. misalnya, jika Anda melakukan MVC, pengontrol Anda dapat menjalankan dao.load () dan kemudian membuat pengecualian saat mencoba mengakses objek proxy nanti jika tidak ada sesi yang valid. melakukan dao.get () akan mengembalikan objek sebenarnya ke kontroler terlepas dari sesi (dengan asumsi itu ada)
dev
Masalah yang dijelaskan oleh @Vicky dapat menyebabkan sakit kepala, dan saya tidak melihat keuntungan apa pun darinya. Dalam beberapa kasus, saya juga memerlukan pengenal untuk kueri parametrized lebih lanjut. Tetapi karena proxy objek sudah ada dalam sesi, pengambil pengenal mengembalikan null. Mengapa mereka mengambil proxy alih-alih contoh nyata jika proxy itu ada dalam sesi?
djmj
15

Setidaknya dalam nhibernate, session.Get (id) akan memuat objek dari database, sedangkan session.Load (id) hanya membuat objek proxy untuk itu tanpa meninggalkan server Anda. Bekerja seperti setiap properti lazy-loaded lainnya di POCO Anda (atau POJOs :). Anda kemudian dapat menggunakan proxy ini sebagai referensi ke objek itu sendiri untuk membuat hubungan, dll.

Anggap saja seperti memiliki objek yang hanya menyimpan Id dan yang akan memuat sisanya jika Anda membutuhkannya. Jika Anda hanya menyebarkannya untuk membuat hubungan (seperti FK), id adalah semua yang Anda butuhkan.

Jorge Alves
sumber
jadi Anda ingin mengatakan load (id) pertama-tama akan masuk ke database untuk memeriksa apakah itu id valid atau tidak dan kemudian akan mengembalikan objek proxy dan ketika properti objek ini diakses, itu mengenai database lagi? bukankah itu skenario yang tidak mungkin? dua kueri untuk memuat satu objek?
faisalbhagat
Tidak, load (id) tidak akan memvalidasi id sama sekali sehingga tidak ada perjalanan bolak-balik ke DB. Gunakan hanya jika Anda yakin yakin itu valid.
Jorge Alves
9

session.load () akan selalu mengembalikan "proxy" (istilah Hibernate) tanpa menyentuh database. Dalam Hibernate, proxy adalah objek dengan nilai pengenal yang diberikan, propertinya belum diinisialisasi, hanya terlihat seperti objek palsu sementara. Jika tidak ada baris yang ditemukan, ObjectNotFoundException akan muncul.

session.get () selalu menekan database dan mengembalikan objek sebenarnya, sebuah objek yang mewakili baris database, bukan proxy. Jika tidak ada baris yang ditemukan, itu mengembalikan null.

Performa dengan metode ini juga membuat berbeda. antara dua ...

Vishal Sharma
sumber
3

Satu poin ekstra lagi ::

Metode get kelas Sesi Hibernasi mengembalikan null jika objek tidak ditemukan di cache dan juga di database. sedangkan metode load () melontarkan ObjectNotFoundException jika objek tidak ditemukan di cache serta di database tetapi tidak pernah mengembalikan null.

madhu_karnati
sumber
2

Satu konsekuensi tidak langsung dari penggunaan "load" daripada "get" adalah penguncian optimis menggunakan atribut version mungkin tidak berfungsi seperti yang Anda harapkan. Jika pemuatan hanya membuat proxy dan tidak membaca dari database, properti versi tidak dimuat. Versi tersebut hanya akan dimuat ketika / jika Anda nanti merujuk ke properti pada objek, memicu pemilihan. Sementara itu, sesi lain dapat memperbarui objek, dan sesi Anda tidak akan memiliki versi asli yang diperlukan untuk melakukan pemeriksaan kunci optimis - sehingga pembaruan sesi Anda akan menimpa pembaruan sesi lain tanpa peringatan.

Berikut adalah upaya untuk membuat sketsa skenario ini dengan dua sesi yang bekerja dengan objek dengan pengenal yang sama. Versi awal untuk objek di DB adalah 10.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

Kami sebenarnya ingin komitmen sesi 1 gagal dengan pengecualian kunci optimis, tetapi akan berhasil di sini.

Menggunakan "get" daripada "load" akan mengatasi masalah tersebut, karena get akan segera mengeluarkan pilihan, dan nomor versi akan dimuat pada waktu yang tepat untuk pemeriksaan kunci yang optimis.

SteveT
sumber
0

Juga kita harus berhati-hati saat menggunakan load karena akan memunculkan eksepsi jika obyek tidak ada. Kita harus menggunakannya hanya jika kita yakin objek itu ada.

Sanjay
sumber
0

Penjelasan yang sangat baik ditemukan di http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
Ini akan selalu mengembalikan "proxy" (istilah Hibernate) tanpa mengenai database.
Dalam Hibernate, proxy adalah objek dengan nilai pengenal yang diberikan, propertinya belum diinisialisasi, hanya terlihat seperti objek palsu sementara.
Itu akan selalu mengembalikan objek proxy dengan nilai identitas yang diberikan, bahkan nilai identitas tidak ada dalam database. Namun, ketika Anda mencoba untuk menginisialisasi proxy dengan mengambil propertinya dari database, itu akan mengenai database dengan pernyataan pilih. Jika tidak ada baris yang ditemukan, ObjectNotFoundException akan muncul.
session.get ():
Itu selalu mengenai database (jika tidak ditemukan di cache) dan mengembalikan objek sebenarnya, sebuah objek yang mewakili baris database, bukan proxy.
Jika tidak ada baris yang ditemukan, itu mengembalikan null.

jack hitam
sumber
0

load () tidak dapat menemukan objek dari cache atau database, pengecualian dilempar dan metode load () tidak pernah mengembalikan null.

Metode get () mengembalikan null jika objek tidak dapat ditemukan. Metode load () mungkin mengembalikan proxy alih-alih instance persisten nyata get () tidak pernah mengembalikan proxy.

Yasser Shaikh
sumber