Saya mengalami masalah dalam melakukan transaksi dalam metode @Transactional saya:
methodA() {
methodB()
}
@Transactional
methodB() {
...
em.persist();
...
em.flush();
log("OK");
}
Ketika saya memanggil methodB () dari methodA (), metode tersebut berhasil lolos dan saya dapat melihat "OK" di log saya. Tapi kemudian saya mengerti
Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at methodA()...
- Konteks methodB benar-benar hilang dalam pengecualian - yang tidak masalah menurut saya?
- Sesuatu di dalam methodB () menandai transaksi sebagai rollback saja? Bagaimana saya bisa menemukannya? Apakah ada misalnya cara untuk memeriksa sesuatu seperti
getCurrentTransaction().isRollbackOnly()?
- seperti ini saya bisa melangkah melalui metode dan menemukan penyebabnya.
Jawaban:
Saat Anda menandai metode Anda sebagai
@Transactional
, terjadinya pengecualian apa pun di dalam metode Anda akan menandai TX di sekitarnya hanya sebagai roll-back (bahkan jika Anda menangkapnya). Anda dapat menggunakan atribut@Transactional
anotasi lainnya untuk mencegahnya bergulir kembali seperti:@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)
sumber
noRollbackFor=Exception.class
, tetapi tampaknya tidak berpengaruh - apakah berfungsi untuk pengecualian yang diwariskan?methodC
di posting pertama Anda). KeduanyamethodB
danmethodC
menggunakan TX yang sama dan selalu menggunakan@Transactional
anotasi paling spesifik , jadi ketikamethodC
melempar pengecualian, TX di sekitarnya akan ditandai sebagai rollback-only. Anda juga dapat menggunakan penanda propagasi yang berbeda untuk mencegahnya.EmptyResultDataAccessException
pengecualian pada transaksi hanya-baca dan saya mendapatkan kesalahan yang sama. Mengubah anotasi saya untuk@Transactional(readOnly = true, noRollbackFor = EmptyResultDataAccessException.class)
memperbaiki masalah.@Transactional
pembungkus proxy, yaitu tidak tertangkap . Lihat jawaban lain dari Vojtěch untuk cerita lengkapnya. Mungkin ada@Transactional
metode bertingkat yang dapat menandai transaksi Anda sebagai rollback-only.noRollbackFor
bekerja hanya jikaglobalRollbackOnParticipationFailure=false
Saya akhirnya mengerti masalahnya:
methodA() { methodB() } @Transactional(noRollbackFor = Exception.class) methodB() { ... try { methodC() } catch (...) {...} log("OK"); } @Transactional methodC() { throw new ...(); }
Yang terjadi adalah meskipun
methodB
anotasi memiliki anotasi yang benar,methodC
namun tidak. Saat pengecualian dilemparkan, yang kedua@Transactional
menandai transaksi pertama sebagai Rollback saja.sumber
propagation=requires_new
maka methodB tidak akan melakukan rollback?methodC
harus berada dalam Spring bean / service yang berbeda atau diakses melalui proxy Spring. Jika tidak, Spring tidak akan memiliki kemungkinan untuk mengetahui tentang pengecualian Anda. Hanya pengecualian yang melewati@Transactional
anotasi yang dapat menandai transaksi sebagai rollback-only.Untuk mengambil pengecualian penyebab dengan cepat tanpa perlu membuat kode ulang atau membuat ulang, aktifkan breakpoint
org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3
dan naik di tumpukan, biasanya ke beberapa Interceptor. Di sana Anda dapat membaca pengecualian penyebab dari beberapa blok tangkapan.
sumber
org.hibernate.jpa.internal.TransactionImpl
org.hibernate.engine.transaction.internal.TransactionImpl
dan metodenya adalahsetRollbackOnly
.Saya berjuang dengan pengecualian ini saat menjalankan aplikasi saya.
Akhirnya masalahnya ada pada query sql . Maksud saya kueri itu salah.
harap verifikasi kueri Anda. Ini saran saya
sumber
Cari pengecualian yang dilempar dan ditangkap di
...
bagian kode Anda. Pengecualian aplikasi runtime dan rollback menyebabkan rollback saat dikeluarkan dari metode bisnis bahkan jika tertangkap di beberapa tempat lain.Anda dapat menggunakan konteks untuk mengetahui apakah transaksi ditandai untuk rollback.
@Resource private SessionContext context; context.getRollbackOnly();
sumber
SessionContext
kelas standar di Spring? Menurut saya ini agak EJB3 dan tidak terdapat dalam Aplikasi Musim Semi saya.TransactionAspectSupport.currentTransactionStatus().isRollbackOnly()
tersedia.Menemukan penjelasan yang bagus dengan solusi: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/
1) Hapus @Transacional dari metode bersarang jika tidak benar-benar memerlukan kontrol transaksi. Jadi meski ada pengecualian, itu hanya menggelembung dan tidak memengaruhi hal-hal transaksional.
ATAU:
2) jika metode bersarang memang membutuhkan kontrol transaksi, jadikan sebagai REQUIRE_NEW untuk kebijakan penyebaran seperti itu bahkan jika melontarkan pengecualian dan ditandai sebagai rollback saja, pemanggil tidak akan terpengaruh.
sumber
nonaktifkan transactionmanager di Bean.xml Anda
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
komentari baris ini, dan Anda akan melihat pengecualian yang menyebabkan rollback;)
sumber
terapkan kode di bawah ini di productRepository
@Query("update Product set prodName=:name where prodId=:id ") @Transactional @Modifying int updateMyData(@Param("name")String name, @Param("id") Integer id);
sedangkan di tes junit terapkan kode di bawah ini
@Test public void updateData() { int i=productRepository.updateMyData("Iphone",102); System.out.println("successfully updated ... "); assertTrue(i!=0); }
itu berfungsi dengan baik untuk kode saya
sumber