JPA EntityManager: Mengapa menggunakan bertahan() lebih merge()?
EntityManager.merge()
dapat menyisipkan objek baru dan memperbarui yang sudah ada.
Mengapa seseorang ingin menggunakan bertahan()
(yang hanya dapat membuat objek baru)?
920
15
Cara baik akan menambah suatu entitas ke PersistenceContext, perbedaannya adalah dalam apa yang anda lakukan dengan entitas setelah itu.
Bertahan mengambil suatu entitas contoh, menambahkan ke konteks dan membuat contoh yang berhasil (yaitu masa depan pembaruan untuk entitas yang akan dilacak).
Menggabungkan menciptakan sebuah instance baru dari entitas, salinan negara dari yang disediakan badan, dan membuat salinan baru berhasil. Contoh anda lulus dalam tidak akan berhasil (setiap perubahan yang anda buat tidak akan menjadi bagian dari transaksi - kecuali anda memanggil bergabung lagi).
Mungkin contoh kode yang akan membantu.
Skenario 1 dan 3 yang kira-kira setara, tetapi ada beberapa situasi di mana anda'd ingin menggunakan Skenario 2.
Bertahan dan merge adalah untuk dua tujuan yang berbeda (mereka tidak't alternatif pada semua).
(diedit untuk memperluas perbedaan informasi)
bertahan:
gabung:
bertahan() efisiensi:
bertahan() semantik:
Contoh:
Cara ini hanya ada 1 yang terpasang objek untuk mendaftar di badan pengelola.
merge() untuk entitas dengan identitas adalah sesuatu seperti:
Meskipun jika terhubung ke MySQL merge() bisa seefisien bertahan() menggunakan panggilan untuk MENYISIPKAN dengan ON DUPLICATE KEY UPDATE option, JPA adalah pemrograman tingkat tinggi dan anda dapat't menganggap ini akan menjadi kasus di mana-mana.
Jika anda're menggunakan ditugaskan generator, menggunakan gabungan bukannya bertahan dapat menyebabkan berlebihan pernyataan SQL, oleh karena itu mempengaruhi kinerja.
Juga, panggilan bergabung untuk dikelola badan adalah juga kesalahan sejak dikelola badan secara otomatis dikelola oleh Hibernate dan negara mereka disinkronkan dengan database rekam oleh kotor memeriksa mekanisme pada flushing Kegigihan Konteks.
Untuk memahami bagaimana semua ini bekerja, pertama-tama anda harus tahu bahwa Hibernate pergeseran pengembang pola pikir dari pernyataan SQL untuk entitas negara transisi.
Setelah suatu entitas yang dikelola secara aktif oleh Hibernate, semua perubahan akan secara otomatis disebarkan ke database.
Hibernate monitor saat ini melekat di badan. Tapi bagi suatu entitas untuk menjadi berhasil, itu harus dalam entitas negara.
Pertama, kita harus mendefinisikan semua entitas serikat:
Baru dibuat objek yang belum pernah berhubungan dengan Hibernate
Sesi
(a.k.aKetekunan
Konteks) dan tidak dipetakan ke tabel database turut dianggap Baru (Transient) negara.Untuk menjadi tetap perlu kita baik secara eksplisit menyebut
EntityManager#bertahan
metode atau menggunakan transitif ketekunan mekanisme.Gigih badan telah dikaitkan dengan tabel database-turut dan itu dikelola oleh arus berjalan Ketekunan Konteks. Setiap perubahan yang dibuat untuk entitas tersebut akan terdeteksi dan disebarkan ke database (selama Sesi flush-waktu). Dengan Hibernate, kita tidak lagi harus melakukan INSERT/UPDATE/DELETE pernyataan. Hibernate menggunakan transaksional write-behind gaya kerja dan perubahan akan disinkronkan di jawab saat ini, selama arus
Sesi
flush-waktu.Setelah berjalan saat ini Kegigihan Konteks ditutup semua yang sebelumnya dikelola badan menjadi terpisah. Perubahan berturut-turut tidak akan lagi dapat dilacak dan tidak ada sinkronisasi database otomatis akan terjadi.
Untuk mengasosiasikan sebuah entitas terpisah untuk aktif Hibernate Sesi, anda dapat memilih salah satu dari pilihan berikut:
Hibernate (tapi tidak JPA 2.1) mendukung reattaching melalui Sesi#metode update. Hibernate Sesi hanya dapat mengaitkan satu Kesatuan objek untuk database tertentu-turut. Hal ini karena Kegigihan Konteks bertindak sebagai aplikasi yang di-cache memori (first level cache) dan hanya satu nilai (entity) adalah terkait dengan kunci yang diberikan (tipe entitas dan database pengenal). Suatu entitas dapat disambungkan hanya jika tidak ada yang lain JVM objek (pencocokan database yang sama-turut) sudah terkait untuk saat ini Hibernate Sesi.
Penggabungan ini akan menyalin entitas terpisah negara (sumber) entitas yang dikelola contoh (tujuan). Jika penggabungan entitas tidak memiliki setara dalam Sesi saat ini, satu akan diambil dari database. Terpisah objek instance akan terus tetap terpisah bahkan setelah operasi gabungan.
Meskipun JPA tuntutan yang dikelola badan hanya diperbolehkan untuk dihapus, Hibernate juga dapat menghapus entitas terpisah (tetapi hanya melalui Sesi#menghapus method). Yang dihapus badan hanya dijadwalkan untuk dihapus dan aktual database MENGHAPUS pernyataan akan dijalankan selama Sesi flush-waktu.
Untuk memahami JPA negara transisi yang baik, anda dapat memvisualisasikan diagram berikut:
Atau jika anda menggunakan Hibernate tertentu API:
Saya menyadari bahwa ketika saya menggunakan
em.menggabungkan
, saya mendapat pernyataanPILIH
untuk setiapINSERT
, bahkan ketika tidak ada bidang yang JPA menghasilkan untuk saya-bidang kunci utama adalah UUID yang saya tetapkan sendiri. Saya beralih keem.bertahan(myEntityObject)
dan punyaINSERT
pernyataan itu.JPA spesifikasi kata berikut tentang
bertahan()
.Jadi menggunakan
bertahan()
akan cocok ketika objek harus menjadi terpisah objek. Anda mungkin lebih memilih untuk memiliki kode membuangPersistenceException
sehingga gagal dengan cepat.Meskipun spesifikasi lebih jelas,
bertahan()
mungkin mengatur@GeneratedValue
@Id
untuk sebuah objek.merge()
namun harus memiliki objek dengan@Id
sudah dihasilkan.Ada beberapa perbedaan antara
menggabungkan
danbertahan
(aku akan menghitung lagi mereka yang sudah diposting di sini):D1.
menggabungkan
tidak membuat lulus entitas yang dikelola, melainkan kembali lagi contoh yang berhasil.bertahan
di sisi lain akan membuat lulus entitas yang dikelola:D2. Jika anda menghapus sebuah entitas dan kemudian memutuskan untuk bertahan badan kembali, anda dapat melakukannya hanya dengan bertahan(), karena
menggabungkan
akan membuangIllegalArgumentException
.D3. Jika anda memutuskan untuk mengurus secara manual Id anda (e.g dengan menggunakan Uuid), maka
menggabungkan
operasi akan memicu berikutnya querySELECT
dalam rangka untuk mencari ada entitas dengan ID tersebut, sementarabertahan
mungkin tidak perlu permintaan tersebut.D4. Ada kasus ketika anda hanya tidak mempercayai kode yang memanggil kode anda, dan dalam rangka untuk memastikan bahwa tidak ada data yang diperbarui, melainkan dimasukkan, anda harus menggunakan
bertahan
.Beberapa rincian lebih lanjut tentang gabungan yang akan membantu anda untuk menggunakan gabungan lebih dari bertahan:
Semua informasi di atas diambil dari "Pro JPA 2 Mastering Java™ Ketekunan API" oleh Mike Keith dan Merrick Schnicariol. Bab 6. Bagian pelepasan dan penggabungan. Buku ini sebenarnya adalah buku kedua yang ditujukan untuk JPA oleh penulis. Buku baru ini memiliki banyak informasi baru kemudian mantan satu. Saya benar-benar menyarankan untuk membaca buku ini untuk orang-orang yang akan menjadi serius terlibat dengan JPA. Saya minta maaf untuk anonimously posting pertama saya menjawab.
Saya mendapatkan lazyLoading pengecualian pada badan saya karena saya mencoba untuk mengakses malas dimuat koleksi yang sedang berlangsung.
Apa yang akan saya lakukan adalah dalam permintaan terpisah, mengambil entitas dari sesi dan kemudian mencoba untuk mengakses koleksi dalam halaman jsp yang bermasalah.
Untuk mengatasi hal ini, saya diperbarui entitas yang sama dalam controller dan berlalu ke jsp, meskipun saya bayangkan ketika saya kembali disimpan di sesi itu juga akan dapat diakses meskipun
SessionScope
dan tidak membuangLazyLoadingException
, sebuah modifikasi dari contoh 2:Berikut telah bekerja untuk saya:
Bertahan entitas
Berbeda dengan menggabungkan metode bertahan metode ini cukup sederhana dan intuitif. Skenario yang paling umum dari bertahan metode's penggunaan dapat disimpulkan sebagai berikut:
"Yang baru dibuat instance dari entitas kelas berlalu untuk bertahan metode. Setelah metode ini kembali, entitas dikelola dan direncanakan untuk dimasukkan ke dalam database. Itu mungkin terjadi pada atau sebelum melakukan transaksi atau ketika flush metode ini disebut. Jika referensi entitas entitas lain melalui hubungan ditandai dengan BERTAHAN cascade strategi prosedur ini diterapkan untuk itu juga."
Spesifikasi pergi lebih ke detail, namun, mengingat mereka adalah tidak penting karena ini rincian mencakup lebih atau kurang eksotis situasi saja.
Penggabungan entitas
Dalam perbandingan untuk bertahan, deskripsi gabung's perilaku yang tidak begitu sederhana. Tidak ada skenario utama, karena itu dalam hal bertahan, dan seorang programmer harus ingat semua skenario dalam rangka untuk menulis kode yang benar. Tampaknya bagi saya bahwa JPA desainer ingin memiliki beberapa metode perhatian utama yang akan menangani terpisah entitas (sebagai lawan untuk bertahan metode yang berhubungan dengan entitas baru dibuat terutama.) Penggabungan metode's tugas utama adalah untuk mentransfer dari negara yang tidak dikelola badan (yang dilewatkan sebagai argumen) untuk dikelola mitra dalam ketekunan konteks. Tugas ini, namun, membagi lebih lanjut menjadi beberapa skenario yang memperburuk kejelasan dari keseluruhan metode's perilaku.
Bukannya mengulang-ulang ayat dari JPA spesifikasi saya telah menyiapkan sebuah diagram alur yang secara skematis menggambarkan perilaku dari penggabungan metode:
Jadi, kapan saya harus menggunakan bertahan dan ketika bergabung?
bertahan
menggabungkan
Melalui jawaban ada beberapa detail yang hilang mengenai `Kaskade' id dan generasi. Lihat pertanyaan
Juga, itu adalah layak disebut bahwa anda dapat memiliki
Cascade
penjelasan untuk penggabungan dan bertahan:Cascade.MENGGABUNGKAN
danCascade.BERTAHAN
yang akan diperlakukan sesuai dengan metode yang digunakan.Spec adalah teman anda ;)
Saya menemukan ini penjelasan dari Hibernate docs mencerahkan, karena mengandung use case:
Dari: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html
Skenario X:
Tabel:Spitter (Satu) ,Tabel: Spittles (Banyak) (Spittles adalah Pemilik hubungan dengan FK:spitter_id)
Skenario ini hasil tabungan : Spitter dan kedua Spittles seolah-olah dimiliki oleh yang Sama Spitter.
Pengamatan lain:
gabung()
hanya akan peduli tentang auto-generated id(diuji padaIDENTITAS
danURUTAN
) ketika sebuah record dengan id yang sudah ada di meja anda. Dalam hal inimerge()
akan mencoba untuk memperbarui catatan. Namun, jika id tidak ada atau tidak cocok setiap catatan yang ada,merge()
benar-benar akan mengabaikan hal itu dan meminta db untuk mengalokasikan baru. Hal ini kadang-kadang menjadi sumber dari banyak bug. Jangan gunakanmerge()
untuk memaksa id untuk rekor baru.bertahan()
di sisi lain tidak akan pernah membiarkan anda bahkan melewati sebuah id untuk itu. Itu akan gagal segera. Dalam kasus saya, itu's:hibernate-jpa javadoc memiliki petunjuk:
Anda mungkin datang ke sini untuk meminta nasihat pada saat digunakan bertahan dan ketika menggunakan menggabungkan. Saya berpikir bahwa itu tergantung situasi: seberapa besar kemungkinan itu adalah bahwa anda perlu untuk membuat rekor baru dan bagaimana keras adalah untuk mengambil desak data.
Let's kira anda dapat menggunakan kunci alam/identifier.
try { entityManager.bertahan(entity) }
menangkap(EntityExistsException pengecualian) { / mengambil dan menggabungkan / }
entitas = entityManager.menemukan(key);
jika (entity == null) { entityManager.bertahan(entitas); }
else { / menggabungkan / }
Jika anda don't memiliki kunci alam/identifier, anda'll memiliki waktu yang sulit untuk mengetahui apakah entitas tersebut ada atau tidak, atau bagaimana untuk mencarinya.
Yang menyatu dapat ditangani dalam dua cara:
bertahan(entity) harus digunakan dengan benar-benar entitas baru, untuk menambahkan mereka ke DB (jika badan sudah ada di DB akan ada EntityExistsException melempar).
merge(entity) harus digunakan, untuk menempatkan badan kembali ke kegigihan konteks jika entitas terpisah dan berubah.
Mungkin bertahan adalah menghasilkan MENYISIPKAN pernyataan sql dan menggabungkan UPDATE statement sql (tapi aku'm tidak yakin).