Saya mendapatkan kesalahan hibernasi berikut. Saya dapat mengidentifikasi fungsi yang menyebabkan masalah. Sayangnya ada beberapa panggilan DB dalam fungsi tersebut. Saya tidak dapat menemukan baris yang menyebabkan masalah sejak hibernasi membilas sesi di akhir transaksi. Kesalahan hibernasi yang disebutkan di bawah ini tampak seperti kesalahan umum. Bahkan tidak disebutkan Bean mana yang menyebabkan masalah. Adakah yang akrab dengan kesalahan hibernasi ini?
org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
at org.hibernate.jdbc.BatchingBatcher.checkRowCount(BatchingBatcher.java:93)
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:79)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:195)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:584)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransacti
onManager.java:500)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManag
er.java:473)
at org.springframework.transaction.interceptor.TransactionAspectSupport.doCommitTransactionAfterReturning(Transaction
AspectSupport.java:267)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
Jawaban:
Tanpa kode dan pemetaan untuk transaksi Anda, hampir tidak mungkin untuk menyelidiki masalahnya.
Namun, untuk mendapatkan penanganan yang lebih baik tentang penyebab masalah, coba yang berikut ini:
Semoga membantu.
sumber
Saya mendapat pengecualian yang sama saat menghapus catatan dengan Id yang tidak ada sama sekali. Jadi periksa bahwa catatan yang Anda perbarui / Hapus benar-benar ada di DB
sumber
Solusi: Dalam file pemetaan Hibernasi untuk properti id, jika Anda menggunakan kelas generator apa pun, untuk properti itu Anda tidak boleh menyetel nilai secara eksplisit dengan menggunakan metode penyetel.
Jika Anda menyetel nilai properti Id secara eksplisit, ini akan menyebabkan kesalahan di atas. Periksa ini untuk menghindari kesalahan ini. atau Kesalahannya muncul ketika Anda menyebutkan dalam file pemetaan generator bidang = "native" atau "incremental" dan di DATABASE Anda tabel yang dipetakan bukan auto_incremented Solusi: Buka DATABASE Anda dan perbarui tabel Anda untuk menyetel auto_increment
sumber
Ini terjadi pada saya sekali secara tidak sengaja ketika saya menetapkan ID tertentu ke beberapa objek (pengujian) dan kemudian saya mencoba menyimpannya di database. Masalahnya adalah bahwa dalam database terdapat kebijakan khusus untuk menyiapkan ID objek. Hanya saja, jangan berikan ID jika Anda memiliki kebijakan di tingkat Hibernasi.
sumber
Dalam kasus saya, saya sampai pada pengecualian ini dalam dua kasus serupa:
@Transactional
saya mendapat panggilan ke layanan lain (dengan waktu respons yang lama). Metode memperbarui beberapa properti entitas (setelah metode, entitas masih ada di database). Jika pengguna meminta metode dua kali (karena menurutnya itu tidak berfungsi pertama kali) saat keluar dari metode transaksional untuk kedua kalinya, Hibernate mencoba memperbarui entitas yang sudah mengubah statusnya dari awal transaksi. Saat Hibernate mencari entitas dalam status, dan menemukan entitas yang sama tetapi sudah diubah oleh permintaan pertama, itu membuat pengecualian karena tidak dapat memperbarui entitas. Ini seperti konflik di GIT.Kesimpulan: dalam kasus saya, itu bukanlah masalah yang dapat ditemukan di dalam kode. Pengecualian ini dilemparkan ketika Hibernate menemukan bahwa entitas yang pertama kali diambil dari database berubah selama transaksi saat ini , sehingga tidak dapat memindahkannya ke database karena Hibernate tidak tahu versi mana yang benar dari entitas: yang saat ini pengambilan transaksi di awal; atau yang sudah tersimpan di database.
Solusi: untuk mengatasi masalah ini, Anda harus bermain-main dengan Hibernate LockMode untuk menemukan yang paling sesuai dengan kebutuhan Anda.
sumber
LockMode.READ
atauLockMode.OPTIMISTIC
.Saya baru saja mengalami masalah ini dan menemukan saya sedang menghapus catatan dan mencoba memperbaruinya setelah itu dalam transaksi Hibernate.
sumber
Ini bisa terjadi saat pemicu mengeksekusi kueri DML (modifikasi data) tambahan yang memengaruhi jumlah baris. Solusi saya adalah menambahkan yang berikut ini di bagian atas pemicu saya:
sumber
Saya menghadapi masalah yang sama. Kode berfungsi di lingkungan pengujian. Tapi itu tidak bekerja di lingkungan pementasan.
org.hibernate.jdbc.BatchedTooManyRowsAffectedException: Batch update returned unexpected row count from update [0]; actual row count: 3; expected: 1
Masalahnya adalah tabel tersebut memiliki entri tunggal untuk setiap kunci utama dalam menguji tabel DB. Tetapi dalam pementasan DB ada beberapa entri untuk kunci utama yang sama. (Masalahnya adalah dalam pementasan DB, tabel tidak memiliki batasan kunci utama juga ada banyak entri.)
Jadi setiap kali operasi pembaruan itu gagal. Ia mencoba untuk memperbarui catatan tunggal dan mengharapkan untuk mendapatkan jumlah pembaruan sebagai 1. Tetapi karena ada 3 catatan dalam tabel untuk kunci utama yang sama, Hasil pembaruan menghitung menemukan 3. Karena jumlah pembaruan yang diharapkan dan jumlah pembaruan hasil aktual tidak cocok , Ini melempar pengecualian dan memutar kembali.
Setelah saya menghapus semua catatan yang memiliki kunci utama duplikat dan menambahkan kendala kunci utama. Ini bekerja dengan baik.
Hibernate - Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
jumlah baris aktual: 0 // berarti tidak ada catatan yang ditemukan untuk memperbarui
pembaruan: 0 // berarti tidak ada catatan yang ditemukan sehingga tidak ada pembaruan yang
diharapkan: 1 // berarti diharapkan setidaknya 1 catatan dengan kunci dalam tabel db.
Di sini masalahnya adalah kueri mencoba memperbarui catatan untuk beberapa kunci, Tetapi hibernasi tidak menemukan catatan apa pun dengan kunci tersebut.
sumber
Seperti yang dikatakan Julius , ini terjadi ketika pembaruan Terjadi pada Objek yang turunannya dihapus. (Mungkin karena ada kebutuhan akan pembaruan untuk seluruh Objek Ayah dan terkadang kami lebih memilih untuk menghapus anak-anak dan memasukkannya kembali pada Ayah (baru, lama tidak masalah) bersama dengan pembaruan lain yang dapat dimiliki ayah pada salah satu itu bidang polos lainnya) Jadi ... agar ini berfungsi, hapus anak-anak (dalam Transaksi) dengan memanggil
childrenList.clear()
(Jangan mengulang melalui anak-anak dan menghapus masing-masing dengan beberapachildDAO.delete(childrenList.get(i).delete()))
dan pengaturan@OneToMany(cascade = CascadeType.XXX ,orphanRemoval=true)
di Sisi Objek Ayah. Kemudian perbarui ayah (fatherDAO.update (ayah)). (Ulangi untuk setiap objek ayah) Hasilnya adalah bahwa hubungan anak-anak dengan ayah mereka dilepas dan kemudian mereka dipindahkan sebagai yatim piatu oleh kerangka kerja.sumber
Saya mengalami masalah ini di mana kami memiliki satu-banyak hubungan.
Dalam file pemetaan hbm hibernate untuk master, untuk objek dengan pengaturan tipe set, ditambahkan
cascade="save-update"
dan berfungsi dengan baik.Tanpa ini, secara default hibernasi mencoba memperbarui untuk catatan yang tidak ada dan dengan melakukan itu ia menyisipkan.
sumber
Hal ini juga dapat terjadi ketika Anda mencoba untuk
UPDATE
sebuah PRIMARY KEY .sumber
Cara lain untuk mendapatkan kesalahan ini adalah jika Anda memiliki item null dalam koleksi.
sumber
Saya mendapat masalah yang sama dan saya memverifikasi ini mungkin terjadi karena kunci utama kenaikan otomatis. Untuk mengatasi masalah ini, jangan masukkan nilai kenaikan otomatis dengan kumpulan data. Masukkan data tanpa kunci utama.
sumber
Ini terjadi ketika Anda mencoba untuk menghapus objek yang sama dan kemudian memperbarui objek yang sama, gunakan ini setelah menghapus
session.clear ();
sumber
Ini terjadi pada saya juga, karena saya memiliki id saya sebagai Long, dan saya menerima dari tampilan nilai 0, dan ketika saya mencoba untuk menyimpan dalam database saya mendapatkan kesalahan ini, kemudian saya memperbaikinya dengan mengatur id ke null.
sumber
Saya mengalami masalah ini ketika saya secara manual memulai dan melakukan transaksi di dalam metode yang dijelaskan sebagai
@Transactional
. Saya memperbaiki masalah dengan mendeteksi apakah transaksi aktif sudah ada.//Detect underlying transaction if (session.getTransaction() != null && session.getTransaction().isActive()) { myTransaction = session.getTransaction(); preExistingTransaction = true; } else { myTransaction = session.beginTransaction(); }
Kemudian saya mengizinkan Spring untuk menangani melakukan transaksi.
private void finishTransaction() { if (!preExistingTransaction) { try { tx.commit(); } catch (HibernateException he) { if (tx != null) { tx.rollback(); } log.error(he); } finally { if (newSessionOpened) { SessionFactoryUtils.closeSession(session); newSessionOpened = false; maxResults = 0; } } } }
sumber
Ini terjadi ketika Anda mendeklarasikan JSF Managed Bean sebagai
@RequestScoped;
kapan Anda harus mendeklarasikan sebagai
@SessionScoped;
Salam;
sumber
Saya mendapat kesalahan ini ketika saya mencoba memperbarui objek dengan id yang tidak ada di database. Alasan kesalahan saya adalah bahwa saya telah menetapkan properti dengan nama 'id' secara manual ke sisi klien JSON-representasi dari objek dan kemudian ketika deserialisasi objek di sisi server, properti 'id' ini akan menimpa variabel instan ( juga disebut 'id') yang seharusnya dihasilkan oleh Hibernate. Jadi berhati-hatilah terhadap benturan penamaan jika Anda menggunakan Hibernate untuk menghasilkan pengenal.
sumber
Saya juga menemukan tantangan yang sama. Dalam kasus saya, saya memperbarui objek yang bahkan tidak ada, menggunakan
hibernateTemplate
.Sebenarnya dalam aplikasi saya, saya mendapatkan objek DB untuk diperbarui. Dan saat memperbarui nilainya, saya juga memperbarui ID-nya secara tidak sengaja, dan melanjutkan untuk memperbaruinya dan menemukan kesalahan tersebut.
Saya menggunakan
hibernateTemplate
untuk operasi CRUD.sumber
Setelah membaca semua jawaban tidak menemukan siapa pun untuk berbicara tentang atribut terbalik dari hibernate.
Menurut pendapat saya, Anda juga harus memverifikasi dalam pemetaan hubungan Anda apakah kata kunci invers diatur dengan tepat. Kata kunci terbalik dibuat untuk menentukan sisi mana yang menjadi pemilik untuk menjaga hubungan. Prosedur untuk memperbarui dan memasukkan berbeda-beda sesuai dengan atribut ini.
Misalkan kita memiliki dua tabel:
principal_table , middle_table
dengan hubungan satu dengan banyak . Kelas pemetaan hiberntate adalah Principal dan Middle masing-masing.
Jadi kelas Kepala Sekolah memiliki SET objek Tengah . File pemetaan xml harus seperti berikut:
<hibernate-mapping> <class name="path.to.class.Principal" table="principal_table" ...> ... <set name="middleObjects" table="middle_table" inverse="true" fetch="select"> <key> <column name="PRINCIPAL_ID" not-null="true" /> </key> <one-to-many class="path.to.class.Middel" /> </set> ...
Karena invers disetel ke "true", itu berarti kelas "Menengah" adalah pemilik hubungan, jadi kelas Kepala Sekolah TIDAK AKAN MEMPERBARUI hubungan tersebut.
Jadi prosedur update bisa diimplementasikan seperti ini:
session.beginTransaction(); Principal principal = new Principal(); principal.setSomething("1"); principal.setSomethingElse("2"); Middle middleObject = new Middle(); middleObject.setSomething("1"); middleObject.setPrincipal(principal); principal.getMiddleObjects().add(middleObject); session.saveOrUpdate(principal); session.saveOrUpdate(middleObject); // NOTICE: you will need to save it manually session.getTransaction().commit();
Ini berhasil untuk saya, tetapi Anda dapat menyarankan beberapa edisi untuk meningkatkan solusinya. Dengan begitu kita semua akan belajar.
sumber
Dalam kasus kami, kami akhirnya menemukan akar penyebab StaleStateException.
Faktanya kami menghapus baris dua kali dalam satu sesi hibernasi. Sebelumnya kami menggunakan ojdbc6 lib, dan ini ok dalam versi ini.
Tetapi ketika kami meningkatkan ke odjc7 atau ojdbc8, menghapus rekaman dua kali menimbulkan pengecualian. Ada bug di kode kami di mana kami menghapus dua kali, tapi itu tidak terbukti di ojdbc6.
Kami dapat mereproduksi dengan potongan kode ini:
Detail detail = getDetail(Long.valueOf(1396451)); session.delete(detail); session.flush(); session.delete(detail); session.flush();
Pada hibernasi siram pertama berjalan dan membuat perubahan dalam database. Selama 2 flush hibernate membandingkan objek sesi dengan rekaman tabel aktual, tetapi tidak dapat menemukannya, oleh karena itu pengecualian.
sumber
Masalah ini terutama terjadi saat kita mencoba menyimpan atau memperbarui objek yang sudah diambil ke dalam memori oleh sesi yang sedang berjalan. Jika Anda telah mengambil objek dari sesi dan Anda mencoba untuk memperbarui di database, pengecualian ini mungkin dilemparkan.
Saya menggunakan session.evict (); untuk menghapus cache yang disimpan dalam mode hibernate terlebih dahulu atau jika tidak ingin mengambil resiko kehilangan data, lebih baik kamu membuat objek lain untuk menyimpan data temp.
try { if(!session.isOpen()) { session=EmployeyDao.getSessionFactory().openSession(); } tx=session.beginTransaction(); session.evict(e); session.saveOrUpdate(e); tx.commit();; EmployeyDao.shutDown(session); } catch(HibernateException exc) { exc.printStackTrace(); tx.rollback(); }
sumber
Hibernate 5.4.1 dan HHH-12878 masalah
Sebelum Hibernate 5.4.1, pengecualian kegagalan penguncian yang optimis (misalnya,
StaleStateException
atauOptimisticLockException
) tidak menyertakan pernyataan gagal.Masalah HHH-12878 dibuat untuk meningkatkan Hibernate sehingga saat melontarkan pengecualian penguncian yang optimis,
PreparedStatement
implementasi JDBC juga dicatat:if ( expectedRowCount > rowCount ) { throw new StaleStateException( "Batch update returned unexpected row count from update [" + batchPosition + "]; actual row count: " + rowCount + "; expected: " + expectedRowCount + "; statement executed: " + statement ); }
Waktu Pengujian
Pertama, kita akan mendefinisikan
Post
entitas yang mendefinisikan@Version
properti, sehingga memungkinkan mekanisme penguncian optimis implisit :@Entity(name = "Post") @Table(name = "post") public class Post { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; private String title; @Version private short version; public Long getId() { return id; } public Post setId(Long id) { this.id = id; return this; } public String getTitle() { return title; } public Post setTitle(String title) { this.title = title; return this; } public short getVersion() { return version; } }
Kami akan mengaktifkan pengumpulan JDBC menggunakan 3 properti konfigurasi berikut:
properties.put("hibernate.jdbc.batch_size", "5"); properties.put("hibernate.order_inserts", "true"); properties.put("hibernate.order_updates", "true");
Kami akan membuat 3
Post
entitas:doInJPA(entityManager -> { for (int i = 1; i <= 3; i++) { entityManager.persist( new Post() .setTitle(String.format("Post no. %d", i)) ); } });
Dan Hibernate akan menjalankan penyisipan batch JDBC:
SELECT nextval ('hibernate_sequence') SELECT nextval ('hibernate_sequence') SELECT nextval ('hibernate_sequence') Query: [ INSERT INTO post (title, version, id) VALUES (?, ?, ?) ], Params:[ (Post no. 1, 0, 1), (Post no. 2, 0, 2), (Post no. 3, 0, 3) ]
Jadi, kami tahu bahwa batching JDBC berfungsi dengan baik.
Sekarang, mari kita tiru masalah penguncian optimis:
doInJPA(entityManager -> { List<Post> posts = entityManager.createQuery(""" select p from Post p """, Post.class) .getResultList(); posts.forEach( post -> post.setTitle( post.getTitle() + " - 2nd edition" ) ); executeSync( () -> doInJPA(_entityManager -> { Post post = _entityManager.createQuery(""" select p from Post p order by p.id """, Post.class) .setMaxResults(1) .getSingleResult(); post.setTitle(post.getTitle() + " - corrected"); }) ); });
Transaksi pertama memilih semua
Post
entitas dan mengubahtitle
properti.Namun, sebelum yang pertama
EntityManager
dihapus, kita akan menjalankan transisi kedua menggunakanexecuteSync
metode tersebut.Transaksi kedua mengubah yang pertama
Post
, jadiversion
akan bertambah:Query:[ UPDATE post SET title = ?, version = ? WHERE id = ? AND version = ? ], Params:[ ('Post no. 1 - corrected', 1, 1, 0) ]
Sekarang, ketika transaksi pertama mencoba untuk membersihkan
EntityManager
, kita akan mendapatkanOptimisticLockException
:Query:[ UPDATE post SET title = ?, version = ? WHERE id = ? AND version = ? ], Params:[ ('Post no. 1 - 2nd edition', 1, 1, 0), ('Post no. 2 - 2nd edition', 1, 2, 0), ('Post no. 3 - 2nd edition', 1, 3, 0) ] o.h.e.j.b.i.AbstractBatchImpl - HHH000010: On release of batch it still contained JDBC statements o.h.e.j.b.i.BatchingBatch - HHH000315: Exception executing batch [ org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed: PgPreparedStatement [ update post set title='Post no. 3 - 2nd edition', version=1 where id=3 and version=0 ] ], SQL: update post set title=?, version=? where id=? and version=?
Jadi, Anda perlu memutakhirkan ke Hibernate 5.4.1 atau yang lebih baru untuk mendapatkan manfaat dari peningkatan ini.
sumber
Ini terjadi jika Anda mengubah sesuatu dalam kumpulan data menggunakan kueri sql asli tetapi objek yang bertahan untuk kumpulan data yang sama ada di cache sesi. Gunakan session.evict (yourObject);
sumber
Hibernasi menyimpan cache objek dari sesi. Jika objek diakses dan dimodifikasi oleh lebih dari 1 pengguna maka
org.hibernate.StaleStateException
dapat dibuang. Ini dapat diselesaikan dengan menggabungkan / menyegarkan metode entitas sebelum menyimpan atau menggunakan kunci. Info lebih lanjut: http://java-fp.blogspot.lt/2011/09/orghibernatestalestateexception-batch.htmlsumber
Salah satunya
SessionFactory sf=new Configuration().configure().buildSessionFactory(); Session session=sf.openSession(); UserDetails user=new UserDetails(); session.beginTransaction(); user.setUserName("update user agian"); user.setUserId(12); session.saveOrUpdate(user); session.getTransaction().commit(); System.out.println("user::"+user.getUserName()); sf.close();
sumber
Saya menghadapi pengecualian ini, dan hibernasi berfungsi dengan baik. Saya mencoba memasukkan satu catatan secara manual menggunakan pgAdmin, di sini masalahnya menjadi jelas. Kueri penyisipan SQL mengembalikan 0 penyisipan. dan ada fungsi pemicu yang menyebabkan masalah ini karena mengembalikan null. jadi saya hanya perlu mengaturnya kembali baru. dan akhirnya saya memecahkan masalah tersebut.
harapan yang membantu tubuh mana pun.
sumber
Saya mendapat kesalahan ini karena saya keliru memetakan
ID
kolom menggunakanId(x => x.Id, "id").GeneratedBy.**Assigned**();
Masalah diselesaikan dengan menggunakan
Id(x => x.Id, "id").GeneratedBy.**Identity**();
sumber
Ini terjadi pada saya karena saya kehilangan deklarasi ID di kelas kacang.
sumber
Dalam kasus saya, ada masalah dengan Database karena salah satu Stored Procs menghabiskan semua CPU yang menyebabkan waktu respons DB tinggi. Setelah ini terbunuh, masalah diselesaikan.
sumber