Inilah pemahaman saya tentang metode ini. Terutama ini didasarkan pada API meskipun karena saya tidak menggunakan semua ini dalam praktek.
saveOrUpdate
Call, simpan atau perbarui tergantung pada beberapa pemeriksaan. Misalnya jika tidak ada pengidentifikasi, simpan disebut. Kalau tidak, pembaruan disebut.
simpan
Tetap suatu entitas. Akan menetapkan pengidentifikasi jika tidak ada. Jika ada, itu pada dasarnya melakukan pembaruan. Mengembalikan ID yang dihasilkan dari entitas.
perbarui
Upaya untuk mempertahankan entitas menggunakan pengenal yang ada. Jika tidak ada pengidentifikasi, saya yakin ada pengecualian.
saveOrUpdateCopy
Ini sudah usang dan seharusnya tidak lagi digunakan. Sebaliknya ada ...
bergabung
Sekarang di sinilah pengetahuan saya mulai goyah. Yang penting di sini adalah perbedaan antara entitas sementara, terpisah dan gigih. Untuk info lebih lanjut tentang status objek, lihat di sini . Dengan save & update, Anda berurusan dengan objek yang persisten. Mereka ditautkan ke Sesi sehingga Hibernate tahu apa yang telah berubah. Tetapi ketika Anda memiliki objek sementara, tidak ada sesi yang terlibat. Dalam kasus ini, Anda harus menggunakan gabungan untuk pembaruan dan bertahan untuk menyimpan.
bertahan
Seperti disebutkan di atas, ini digunakan pada objek sementara. Itu tidak mengembalikan ID yang dihasilkan.
sumber
update
objek sementara tidak masalah, saya tidak mendapatkan pengecualian.Lihat Forum Hibernate untuk penjelasan tentang perbedaan halus antara bertahan dan menyimpan. Sepertinya perbedaannya adalah waktu pernyataan INSERT akhirnya dieksekusi. Karena save mengembalikan pengidentifikasi, pernyataan INSERT harus dijalankan secara instan terlepas dari kondisi transaksi (yang umumnya merupakan hal yang buruk). Persist tidak akan menjalankan pernyataan di luar transaksi yang sedang berjalan hanya untuk menetapkan pengenal. Simpan / Tetap sama-sama bekerja pada instance sementara , yaitu instance yang belum memiliki pengidentifikasi dan karena itu belum disimpan dalam DB.
Perbarui dan Gabungkan keduanya berfungsi pada instance terpisah , yaitu instance yang memiliki entri yang sesuai dalam DB tetapi saat ini tidak dilampirkan pada (atau dikelola oleh) Sesi. Perbedaan di antara mereka adalah apa yang terjadi pada instance yang diteruskan ke fungsi. pembaruan mencoba memasang kembali instance, yang berarti bahwa tidak boleh ada instance lain dari entitas persisten yang melekat pada Sesi sekarang, jika tidak ada pengecualian yang dilemparkan. menggabungkan , namun, cukup salin semua nilai ke instance persisten di Sesi (yang akan dimuat jika saat ini tidak dimuat). Objek input tidak berubah. Jadi penggabungan lebih umum daripada pembaruan, tetapi dapat menggunakan lebih banyak sumber daya.
sumber
save() - If an INSERT has to be executed to get the identifier, then this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is problematic in a long-running conversation with an extended Session/persistence context.
Bisakah Anda memberi tahu saya bagaimana penyisipan dapat terjadi di luar sesi dan mengapa itu buruk?INSERT
diedit. Akibatnya, dalam kasus tersebut, Anda tidak dapat mengembalikan pengidentifikasi sekarang tanpa membuatnya dan untuk menghasilkan Anda harus menjalankanINSERT
sekarang . Karena, transaksi jangka panjang tidak berjalan sekarang tetapi hanya pada komit, satu-satunya cara untuk mengeksekusiINSERT
sekarang adalah menjalankannya di luar tx.Tautan ini menjelaskan dengan baik:
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
Kita semua memiliki masalah yang jarang kita temui sehingga ketika kita melihatnya lagi, kita tahu kita telah menyelesaikan ini, tetapi tidak ingat bagaimana caranya.
NonUniqueObjectException dilemparkan ketika menggunakan Session.saveOrUpdate () di Hibernate adalah salah satu milik saya. Saya akan menambahkan fungsionalitas baru ke aplikasi yang kompleks. Semua tes unit saya berfungsi dengan baik. Kemudian dalam menguji UI, mencoba untuk menyimpan objek, saya mulai mendapatkan pengecualian dengan pesan "objek yang berbeda dengan nilai pengidentifikasi yang sama sudah dikaitkan dengan sesi." Berikut beberapa contoh kode dari Java Persistence with Hibernate.
Untuk memahami penyebab pengecualian ini, penting untuk memahami objek yang terlepas dan apa yang terjadi ketika Anda memanggil saveOrUpdate () (atau hanya memperbarui ()) pada objek yang terlepas.
Ketika kita menutup Sesi Hibernate individu, objek persisten yang sedang kita kerjakan terlepas. Ini berarti data masih dalam memori aplikasi, tetapi Hibernate tidak lagi bertanggung jawab untuk melacak perubahan pada objek.
Jika kemudian kita memodifikasi objek yang terpisah dan ingin memperbaruinya, kita harus memasang kembali objek tersebut. Selama proses pemasangan kembali, Hibernate akan memeriksa untuk melihat apakah ada salinan lain dari objek yang sama. Jika ada, itu harus memberitahu kami tidak tahu apa salinan "asli" itu lagi. Mungkin perubahan lain dibuat pada salinan lain yang kami harapkan akan disimpan, tetapi Hibernate tidak tahu tentang mereka, karena itu tidak mengelola mereka pada saat itu.
Daripada menyimpan data yang mungkin buruk, Hibernate memberi tahu kami tentang masalah melalui NonUniqueObjectException.
jadi, apa yang akan kita lakukan? Di Hibernate 3, kami memiliki gabungan () (di Hibernate 2, gunakan saveOrUpdateCopy ()). Metode ini akan memaksa Hibernate untuk menyalin perubahan apa pun dari instance terpisah ke instance yang ingin Anda simpan, dan dengan demikian menggabungkan semua perubahan dalam memori sebelum penyimpanan.
Penting untuk dicatat bahwa gabungan mengembalikan referensi ke versi instance yang baru diperbarui. Itu bukan pemasangan kembali item ke Sesi. Jika Anda menguji misalnya kesetaraan (item == item3), Anda akan menemukan itu mengembalikan false dalam kasus ini. Anda mungkin ingin bekerja dengan item3 mulai saat ini.
Penting juga untuk dicatat bahwa Java Persistence API (JPA) tidak memiliki konsep objek yang dilepaskan dan disambungkan, dan menggunakan EntityManager.persist () dan EntityManager.merge ().
Saya telah menemukan secara umum bahwa ketika menggunakan Hibernate, saveOrUpdate () biasanya cukup untuk kebutuhan saya. Saya biasanya hanya perlu menggunakan gabungan ketika saya memiliki objek yang dapat memiliki referensi ke objek dari tipe yang sama. Baru-baru ini, penyebab pengecualian ada dalam kode yang memvalidasi bahwa referensi tidak rekursif. Saya memuat objek yang sama ke sesi saya sebagai bagian dari validasi, menyebabkan kesalahan.
Di mana Anda mengalami masalah ini? Apakah menggabungkan bekerja untuk Anda atau apakah Anda memerlukan solusi lain? Apakah Anda lebih suka untuk selalu menggunakan penggabungan, atau lebih suka menggunakannya hanya sesuai kebutuhan untuk kasus-kasus tertentu
sumber
Sebenarnya perbedaan antara hibernate
save()
danpersist()
metode tergantung pada kelas generator yang kita gunakan.Jika kelas generator kami ditetapkan, maka tidak ada perbedaan antara
save()
danpersist(
) metode. Karena generator 'ditugaskan' berarti, sebagai seorang programmer kita perlu memberikan nilai kunci primer untuk disimpan dalam database dengan benar [Harap Anda tahu konsep generator ini] Dalam kasus selain dari kelas generator yang ditugaskan, misalkan jika nama kelas generator kita adalah Increment means hibernasi itu sendiri akan menetapkan nilai id kunci primer ke dalam database tepat [selain generator yang ditugaskan, hibernasi hanya digunakan untuk menjaga nilai id kunci primer diingat], jadi dalam hal ini jika kita memanggilsave()
ataupersist()
metode maka akan memasukkan catatan ke dalam database secara normal. Tapi dengar masalahnya,save()
metode dapat mengembalikan nilai id kunci primer yang dihasilkan oleh hibernate dan kita dapat melihatnya denganDalam kasus yang sama ini,
persist()
tidak akan pernah memberikan nilai apa pun kepada klien.sumber
Saya menemukan contoh yang bagus yang menunjukkan perbedaan antara semua metode penyimpanan hibernate:
http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorsupdate-persist-example
Secara singkat, menurut tautan di atas:
menyimpan()
bertahan ()
saveOrUpdate ()
Dapat digunakan dengan atau tanpa transaksi, dan seperti halnya save (), jika digunakan tanpa transaksi, entitas yang dipetakan tidak akan disimpan, karena kami membilas sesi.
Hasil masuk atau memperbarui kueri berdasarkan data yang disediakan. Jika data ada di database, pembaruan permintaan dijalankan.
memperbarui()
menggabungkan()
Juga untuk contoh praktis dari semua ini, silakan merujuk ke tautan yang saya sebutkan di atas, itu menunjukkan contoh untuk semua metode yang berbeda ini.
sumber
Seperti yang saya jelaskan dalam artikel ini , Anda harus lebih memilih metode JPA sebagian besar waktu, dan
update
untuk tugas-tugas pemrosesan batch.Entitas JPA atau Hibernate dapat berada di salah satu dari empat negara berikut:
Transisi dari satu negara ke yang lain dilakukan melalui metode EntityManager atau Sesi.
Misalnya, JPA
EntityManager
menyediakan metode transisi status entitas berikut.Hibernate
Session
mengimplementasikan semuaEntityManager
metode JPA dan menyediakan beberapa metode transisi status entitas tambahan sepertisave
,saveOrUpdate
danupdate
.Bertahan
Untuk mengubah status entitas dari Transient (Baru) ke Managed (Persisted), kita dapat menggunakan
persist
metode yang ditawarkan oleh JPAEntityManager
yang juga diwarisi oleh HibernateSession
.Karena itu, ketika menjalankan uji kasus berikut:
Hibernate menghasilkan pernyataan SQL berikut:
Perhatikan bahwa
id
ditugaskan sebelum melampirkanBook
entitas ke Konteks Persistence saat ini. Ini diperlukan karena entitas yang dikelola disimpan dalamMap
struktur di mana kunci dibentuk oleh jenis entitas dan pengenalnya dan nilainya adalah referensi entitas. Ini adalah alasan mengapa JPAEntityManager
dan HibernateSession
dikenal sebagai Cache Tingkat Pertama.Saat memanggil
persist
, entitas hanya dilampirkan ke Konteks Persistence yang sedang berjalan, dan INSERT dapat ditunda hinggaflush
dipanggil.Satu-satunya pengecualian adalah generator IDENTITY yang memicu INSERT segera karena itulah satu-satunya cara ia bisa mendapatkan pengenal entitas. Karena alasan ini, Hibernate tidak dapat memasukkan batch untuk entitas menggunakan generator IDENTITY. Untuk detail lebih lanjut tentang topik ini, lihat artikel ini .
Menyimpan
Khusus Hibernate
save
Metode mendahului JPA dan sudah tersedia sejak awal proyek Hibernate.Untuk melihat bagaimana
save
metode ini bekerja, pertimbangkan uji kasus berikut:Saat menjalankan test case di atas, Hibernate menghasilkan pernyataan SQL berikut:
Seperti yang Anda lihat, hasilnya identik dengan
persist
pemanggilan metode. Namun, tidak sepertipersist
,save
metode mengembalikan pengenal entitas.Untuk lebih jelasnya, lihat artikel ini .
Memperbarui
update
Metode khusus Hibernate dimaksudkan untuk mem-bypass mekanisme pemeriksaan kotor dan memaksa pembaruan entitas pada waktu flush.Untuk melihat bagaimana
update
metode ini bekerja, perhatikan contoh berikut ini yang bertahan suatuBook
entitas dalam satu transaksi, kemudian memodifikasinya saat entitas dalam keadaan terlepas, dan itu memaksa SQL UPDATE menggunakanupdate
pemanggilan metode.Saat menjalankan uji kasus di atas, Hibernate menghasilkan pernyataan SQL berikut:
Perhatikan bahwa
UPDATE
dieksekusi selama flush Konteks Persistence, tepat sebelum komit, dan itulah sebabnyaUpdating the Book entity
pesan dicatat terlebih dahulu.Menggunakan
@SelectBeforeUpdate
untuk menghindari pembaruan yang tidak perluSekarang, UPDATE selalu akan dieksekusi bahkan jika entitas tidak berubah saat dalam keadaan terpisah. Untuk mencegah hal ini, Anda dapat menggunakan
@SelectBeforeUpdate
anotasi Hibernate yang akan memicuSELECT
pernyataan yang diambilloaded state
yang kemudian digunakan oleh mekanisme pemeriksaan kotor.Jadi, jika kita membubuhi keterangan
Book
entitas dengan@SelectBeforeUpdate
anotasi:Dan jalankan test case berikut ini:
Hibernate menjalankan pernyataan SQL berikut:
Perhatikan bahwa, kali ini, tidak ada
UPDATE
dieksekusi karena mekanisme pengecekan kotor Hibernate mendeteksi bahwa entitas tidak dimodifikasi.SimpanOrUpdate
saveOrUpdate
Metode khusus Hibernate hanyalah alias untuksave
danupdate
.Sekarang, Anda dapat menggunakan
saveOrUpdate
saat Anda ingin bertahan suatu entitas atau memaksaUPDATE
seperti yang diilustrasikan oleh contoh berikut.Waspadalah terhadap
NonUniqueObjectException
Salah satu masalah yang dapat terjadi dengan
save
,,update
dansaveOrUpdate
adalah jika Konteks Persistensi sudah berisi referensi entitas dengan id yang sama dan dari jenis yang sama seperti dalam contoh berikut:Sekarang, ketika menjalankan test case di atas, Hibernate akan melempar
NonUniqueObjectException
karena yang keduaEntityManager
sudah berisiBook
entitas dengan pengidentifikasi yang sama seperti yang kita lewatiupdate
, dan Persistence Context tidak dapat menampung dua representasi dari entitas yang sama.Menggabungkan
Untuk menghindarinya
NonUniqueObjectException
, Anda perlu menggunakanmerge
metode yang ditawarkan oleh JPAEntityManager
dan diwarisi oleh HibernateSession
juga.Seperti yang dijelaskan dalam artikel ini ,
merge
mengambil snapshot entitas baru dari database jika tidak ada referensi entitas yang ditemukan dalam Konteks Persistence, dan salinan keadaan entitas terpisah dilewatkan kemerge
metode.Untuk melihat bagaimana
merge
metode ini bekerja, perhatikan contoh berikut ini yang bertahan suatuBook
entitas dalam satu transaksi, kemudian memodifikasinya saat entitas berada dalam keadaan terlepas, dan meneruskan entitas yang terlepas kemerge
dalam Konteks Persistence selanjutnya.Saat menjalankan test case di atas, Hibernate menjalankan pernyataan SQL berikut:
Perhatikan bahwa referensi entitas yang dikembalikan oleh
merge
berbeda dengan yang kita lewati untukmerge
metode ini.Sekarang, meskipun Anda sebaiknya memilih menggunakan JPA
merge
saat menyalin status entitas terpisah, ekstraSELECT
bisa bermasalah saat menjalankan tugas pemrosesan batch.Untuk alasan ini, Anda sebaiknya menggunakan
update
ketika Anda yakin bahwa tidak ada referensi entitas yang sudah dilampirkan ke Konteks Persistence yang sedang berjalan dan bahwa entitas yang terlepas telah dimodifikasi.Untuk detail lebih lanjut tentang topik ini, lihat artikel ini .
Kesimpulan
Untuk bertahan suatu entitas, Anda harus menggunakan
persist
metode JPA . Untuk menyalin status entitas terpisah,merge
harus lebih disukai. Theupdate
Metode ini berguna untuk tugas-tugas pemrosesan batch saja. Thesave
dansaveOrUpdate
hanya alias untukupdate
dan Anda tidak boleh menggunakannya sama sekali.Beberapa pengembang memanggil
save
bahkan ketika entitas sudah dikelola, tetapi ini adalah kesalahan dan memicu peristiwa yang berlebihan karena, untuk entitas yang dikelola, UPDATE secara otomatis ditangani pada waktu flush konteks Persistence.Untuk lebih jelasnya, lihat artikel ini .
sumber
Ketahuilah bahwa jika Anda memanggil pembaruan pada objek yang terpisah, akan selalu ada pembaruan yang dilakukan dalam database apakah Anda mengubah objek atau tidak. Jika bukan itu yang Anda inginkan, Anda harus menggunakan Session.lock () dengan LockMode.None.
Anda harus memanggil pembaruan hanya jika objek diubah di luar ruang lingkup sesi Anda saat ini (ketika dalam mode terpisah).
sumber
Tidak satu pun dari jawaban berikut yang benar. Semua metode ini tampaknya sama, tetapi dalam praktiknya melakukan hal-hal yang benar-benar berbeda. Sulit memberikan komentar pendek. Lebih baik memberikan tautan ke dokumentasi lengkap tentang metode ini: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html
sumber
Tidak ada jawaban di atas yang lengkap. Meskipun jawaban Leo Theobald terlihat sebagai jawaban terdekat.
Poin dasarnya adalah bagaimana hibernate berhadapan dengan status entitas dan bagaimana ia menangani mereka ketika ada perubahan status. Semuanya harus dilihat sehubungan dengan flushes dan commit juga, yang tampaknya semua orang abaikan sama sekali.
JANGAN PERNAH MENGGUNAKAN METODE SIMPAN HIBERNATE. LUPAKAN BAHWA ITU ADA DI HIBERNATE!
Bertahan
Seperti yang semua orang jelaskan, Persist pada dasarnya mentransisikan suatu entitas dari kondisi "Transient" ke "Managed". Pada titik ini, slush atau commit dapat membuat pernyataan insert. Tetapi entitas masih akan tetap dalam status "Dikelola". Itu tidak berubah dengan flush.
Pada titik ini, jika Anda "bertahan" lagi tidak akan ada perubahan. Dan tidak akan ada lagi penyelamatan jika kita mencoba untuk tetap bertahan.
Kegembiraan dimulai ketika kami mencoba mengusir entitas.
Penggusuran adalah fungsi khusus Hibernate yang akan mentransisikan entitas dari "Managed" ke "Detached". Kami tidak dapat memanggil bertahan pada entitas yang terpisah. Jika kita melakukan itu, maka Hibernate memunculkan pengecualian dan seluruh transaksi akan dibatalkan saat komit.
Gabungkan vs Pembaruan
Ini adalah 2 fungsi menarik yang melakukan hal yang berbeda ketika ditangani dengan cara yang berbeda. Keduanya mencoba mentransisikan entitas dari keadaan "Terpisah" ke keadaan "Terkelola". Tetapi melakukannya secara berbeda.
Memahami fakta bahwa Terpisah berarti semacam keadaan "offline". dan dikelola berarti keadaan "Online".
Perhatikan kode di bawah ini:
Kapan kamu melakukan ini? Apa yang kamu pikir akan terjadi? Jika Anda mengatakan ini akan menimbulkan pengecualian, maka Anda benar. Ini akan memunculkan eksepsi karena, penggabungan telah bekerja pada objek entitas, yang merupakan keadaan terpisah. Tapi itu tidak mengubah keadaan objek.
Di belakang layar, gabungan akan menaikkan kueri pemilihan dan pada dasarnya mengembalikan salinan entitas yang dalam keadaan terlampir. Perhatikan kode di bawah ini:
Sampel di atas berfungsi karena penggabungan telah membawa entitas baru ke dalam konteks yang dalam kondisi tetap.
Ketika diterapkan dengan Perbarui yang sama berfungsi dengan baik karena pembaruan tidak benar-benar membawa salinan entitas seperti penggabungan.
Pada saat yang sama dalam pelacakan debug kita dapat melihat bahwa Pembaruan belum meningkatkan kueri SQL dari pilih seperti penggabungan.
menghapus
Dalam contoh di atas saya menggunakan delete tanpa berbicara tentang delete. Hapus pada dasarnya akan mentransisikan entitas dari status terkelola ke status "dihapus". Dan ketika flushed atau commit akan mengeluarkan perintah delete untuk menyimpan.
Namun dimungkinkan untuk membawa entitas kembali ke keadaan "dikelola" dari keadaan "dihapus" menggunakan metode bertahan.
Semoga penjelasan di atas mengklarifikasi keraguan.
sumber