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)?

Mengomentari pertanyaan (2)
Larutan

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.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)

Skenario 1 dan 3 yang kira-kira setara, tetapi ada beberapa situasi di mana anda'd ingin menggunakan Skenario 2.

Komentar (12)

Bertahan dan merge adalah untuk dua tujuan yang berbeda (mereka tidak't alternatif pada semua).

(diedit untuk memperluas perbedaan informasi)

bertahan:

  • Menyisipkan baru mendaftar ke database
  • Melampirkan objek entity manager.

gabung:

  • Cari aplikasi yang terpasang obyek dengan id yang sama dan memperbaruinya.
  • Jika ada update dan kembali sudah terpasang objek.
  • Jika doesn't ada menyisipkan mendaftar baru ke database.

bertahan() efisiensi:

  • Itu bisa menjadi lebih efisien untuk memasukkan baru mendaftar ke database dari penggabungan().
  • Itu doesn't duplikat objek asli.

bertahan() semantik:

  • Membuat yakin bahwa anda memasukkan dan tidak memperbarui dengan kesalahan.

Contoh:

{
    AnyEntity newEntity;
    AnyEntity nonAttachedEntity;
    AnyEntity attachedEntity;

    // Create a new entity and persist it        
    newEntity = new AnyEntity();
    em.persist(newEntity);

    // Save 1 to the database at next flush
    newEntity.setValue(1);

    // Create a new entity with the same Id than the persisted one.
    AnyEntity nonAttachedEntity = new AnyEntity();
    nonAttachedEntity.setId(newEntity.getId());

    // Save 2 to the database at next flush instead of 1!!!
    nonAttachedEntity.setValue(2);
    attachedEntity = em.merge(nonAttachedEntity);

    // This condition returns true
    // merge has found the already attached object (newEntity) and returns it.
    if(attachedEntity==newEntity) {
            System.out.print("They are the same object!");
    }

    // Set 3 to value
    attachedEntity.setValue(3);
    // Really, now both are the same object. Prints 3
    System.out.println(newEntity.getValue());

    // Modify the un attached object has no effect to the entity manager
    // nor to the other objects
    nonAttachedEntity.setValue(42);
}

Cara ini hanya ada 1 yang terpasang objek untuk mendaftar di badan pengelola.

merge() untuk entitas dengan identitas adalah sesuatu seperti:

AnyEntity myMerge(AnyEntity entityToSave) {
    AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
    if(attached==null) {
            attached = new AnyEntity();
            em.persist(attached);
    }
    BeanUtils.copyProperties(attached, entityToSave);

    return attached;
}

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.

Komentar (4)

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 (Sementara)

Baru dibuat objek yang belum pernah berhubungan dengan Hibernate Sesi (a.k.a Ketekunan 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.

  • Terus-Menerus (Berhasil)

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.

  • Terpisah

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:

  • Reattaching

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

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.

  • Dihapus

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:

Komentar (9)

Saya menyadari bahwa ketika saya menggunakan em.menggabungkan, saya mendapat pernyataan PILIH untuk setiap INSERT, bahkan ketika tidak ada bidang yang JPA menghasilkan untuk saya-bidang kunci utama adalah UUID yang saya tetapkan sendiri. Saya beralih ke em.bertahan(myEntityObject) dan punya INSERT pernyataan itu.

Komentar (2)

JPA spesifikasi kata berikut tentang bertahan().

Jika X adalah terpisah objek, EntityExistsException mungkin dilemparkan ketika bertahan operasi ini dijalankan, atau EntityExistsException atau yang lain PersistenceException dapat dilemparkan di siram atau melakukan waktu.

Jadi menggunakan bertahan() akan cocok ketika objek harus menjadi terpisah objek. Anda mungkin lebih memilih untuk memiliki kode membuang PersistenceException 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.

Komentar (3)

Ada beberapa perbedaan antara menggabungkan dan bertahan (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:

//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);

//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);

D2. Jika anda menghapus sebuah entitas dan kemudian memutuskan untuk bertahan badan kembali, anda dapat melakukannya hanya dengan bertahan(), karena menggabungkan akan membuang IllegalArgumentException.

D3. Jika anda memutuskan untuk mengurus secara manual Id anda (e.g dengan menggunakan Uuid), maka menggabungkan operasi akan memicu berikutnya query SELECT dalam rangka untuk mencari ada entitas dengan ID tersebut, sementara bertahan 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.

Komentar (0)

Beberapa rincian lebih lanjut tentang gabungan yang akan membantu anda untuk menggunakan gabungan lebih dari bertahan:

Kembali dikelola contoh lain daripada yang asli entitas adalah bagian penting dari penggabungan proses. Jika entitas misalnya dengan identifier yang sama sudah ada dalam ketekunan konteks, penyedia akan menimpa negara dengan negara dari entitas yang bergabung, tapi berhasil versi yang ada sudah harus dikembalikan ke klien sehingga dapat digunakan. Jika penyedia tidak update Karyawan contoh dalam ketekunan konteks, setiap referensi untuk contoh yang akan menjadi konsisten dengan negara baru yang bergabung di.

Ketika bergabung() dipanggil pada sebuah entitas baru, berperilaku demikian pula untuk bertahan() operasi. Ia menambahkan entitas kegigihan konteks, tapi bukannya menambahkan asli entitas misalnya, menciptakan baru copy dan mengelola hal itu sebagai gantinya. Salinan yang dibuat oleh gabungan() operasi ini bertahan seolah-olah bertahan() method yang dipanggil pada itu.

Di hadapan hubungan, penggabungan() operasi akan mencoba untuk memperbarui dikelola badan untuk point untuk dikelola versi entitas yang dirujuk oleh entitas terpisah. Jika entitas memiliki hubungan suatu objek yang tidak memiliki identitas persisten, hasil dari operasi gabungan adalah tidak terdefinisi. Beberapa penyedia mungkin memungkinkan dikelola copy ke titik non-persistent object, sedangkan yang lain mungkin melemparkan pengecualian segera. Penggabungan() operasi dapat opsional mengalir dalam kasus ini untuk mencegah pengecualian dari terjadi. Kita akan menutupi cascading dari penggabungan() operasi kemudian dalam bagian ini. Jika entitas yang bergabung poin ke dihapus badan, yang IllegalArgumentException exception akan dilempar.

Malas-loading hubungan adalah sebuah kasus khusus dalam operasi gabungan. Jika malas-loading hubungan itu tidak dipicu pada entitas sebelum menjadi terpisah, hubungan itu akan diabaikan ketika entitas gabungan. Jika hubungan itu dipicu sementara berhasil dan kemudian set ke null sedangkan entitas yang terpisah, yang dikelola versi badan juga akan memiliki hubungan yang dibersihkan selama penggabungan."

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.

Komentar (0)

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 membuang LazyLoadingException, sebuah modifikasi dari contoh 2:

Berikut telah bekerja untuk saya:

// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!
Komentar (0)

JPA adalah disangkal besar penyederhanaan dalam domain perusahaan aplikasi yang dibangun pada platform Java. Sebagai pengembang yang harus mengatasi dengan seluk-beluk tua entitas kacang di J2EE aku melihat masuknya JPA antara Java EE spesifikasi sebagai lompatan besar ke depan. Namun, saat menggali lebih dalam JPA rincian yang saya cari hal-hal yang tidak begitu mudah. Dalam artikel ini saya berurusan dengan perbandingan EntityManager ini bergabung dan bertahan metode yang tumpang tindih perilaku yang dapat menyebabkan kebingungan tidak hanya untuk pemula. Selanjutnya Saya mengusulkan generalisasi yang melihat kedua metode sebagai kasus khusus dari lebih umum metode menggabungkan.

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

  • Anda ingin metode yang selalu menciptakan entitas baru dan tidak pernah update entitas. Jika tidak, metode melempar pengecualian sebagai konsekuensi dari primary key keunikan pelanggaran.
  • Batch proses, penanganan entitas dalam stateful cara (lihat Gateway pola).
  • Optimasi kinerja

menggabungkan

  • Anda ingin metode yang baik sisipan atau update sebuah entitas dalam database.
  • Anda ingin menangani entitas dalam bernegara dengan cara (transfer data objek dalam pelayanan)
  • Anda ingin menyisipkan sebuah entitas baru yang mungkin memiliki referensi ke entitas lain yang mungkin tetapi tidak dapat dibuat belum (hubungan harus ditandai MERGE). Misalnya, memasukkan foto baru dengan referensi baik yang baru atau yang sudah ada sebelumnya album.
Komentar (1)

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 dan Cascade.BERTAHAN yang akan diperlakukan sesuai dengan metode yang digunakan.

Spec adalah teman anda ;)

Komentar (0)

Saya menemukan ini penjelasan dari Hibernate docs mencerahkan, karena mengandung use case:

penggunaan dan semantik dari penggabungan() tampaknya membingungkan bagi pengguna baru. Pertama, selama anda tidak mencoba untuk menggunakan objek negara dimuat dalam satu entitas manager di lain entitas baru manajer, anda harus tidak perlu menggunakan gabungan() di semua. Beberapa seluruh aplikasi akan pernah menggunakan metode ini.

Biasanya menggabungkan() digunakan dalam skenario berikut:

  • aplikasi beban suatu objek pada entitas yang pertama manager
  • objek diteruskan ke lapisan presentasi
  • beberapa modifikasi yang dibuat untuk objek
  • objek diteruskan kembali turun ke lapisan logika bisnis
  • aplikasi ini berlanjut modifikasi ini dengan memanggil merge() di kedua badan pengelola

di Sini adalah tepat semantik dari penggabungan():

  • jika tidak dikelola dengan contoh identifier yang sama saat ini terkait dengan masih adanya konteks, copy keadaan objek tertentu ke dikelola contoh
  • jika tidak dikelola contoh saat ini terkait dengan masih adanya konteks, cobalah untuk load dari database, atau membuat yang baru dikelola contoh
  • dikelola contoh dikembalikan
  • diberikan contoh yang tidak menjadi yang terkait dengan kegigihan konteks, tetap terpisah dan biasanya dibuang

Dari: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html

Komentar (0)

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.


        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");     
    spittle3.setSpitter(spitter);               
    dao.addSpittle(spittle3); // 
Komentar (4)

Pengamatan lain:

gabung() hanya akan peduli tentang auto-generated id(diuji pada IDENTITAS dan URUTAN) ketika sebuah record dengan id yang sudah ada di meja anda. Dalam hal ini merge() 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 gunakan merge() 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:

Disebabkan oleh: org.hibernate.PersistentObjectException: entitas terpisah lulus untuk bertahan

hibernate-jpa javadoc memiliki petunjuk:

Melempar: javax.kegigihan.EntityExistsException - jika entitas sudah ada. (Jika entitas yang sudah ada, EntityExistsException mungkin dilemparkan ketika bertahan operasi dipanggil, atau EntityExistsException atau yang lain PersistenceException dapat dilemparkan di siram atau melakukan waktu.)

Komentar (1)

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.

  • Data harus bertahan, tapi once in a while a record ada dan pembaruan yang disebut untuk. Dalam hal ini anda bisa mencoba bertahan dan jika itu melempar EntityExistsException, anda melihat itu dan menggabungkan data:

try { entityManager.bertahan(entity) }

menangkap(EntityExistsException pengecualian) { / mengambil dan menggabungkan / }

  • Desak data yang perlu diperbarui, tetapi sekali-kali tidak ada catatan untuk data yang belum. Dalam hal ini anda mencarinya, dan melakukan bertahan jika entitas yang hilang:

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:

  1. Jika perubahan ini biasanya kecil, menerapkan mereka untuk dikelola badan.
  2. Jika perubahan yang umum, copy ID dari bertahan badan, serta tidak berubah data. Kemudian memanggil EntityManager::menggabungkan() untuk mengganti konten lama.
Komentar (0)

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).

Komentar (3)