Dari http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Rekomendasi tim Spring adalah Anda hanya memberi anotasi pada kelas konkret dengan @Transactional
anotasi, bukan antarmuka anotasi. Anda pasti dapat menempatkan @Transactional
anotasi pada antarmuka (atau metode antarmuka), tetapi ini hanya akan berfungsi seperti yang Anda harapkan jika Anda menggunakan proxy berbasis antarmuka. Fakta bahwa anotasi tidak diwariskan berarti bahwa jika Anda menggunakan proxy berbasis kelas maka pengaturan transaksi tidak akan dikenali oleh infrastruktur proxy berbasis kelas dan objek tidak akan dibungkus dalam proxy transaksional (yang jelas akan buruk ) . Jadi tolong ikuti saran tim Spring dan hanya beri anotasi kelas konkret (dan metode kelas konkret) dengan @Transactional
anotasi.
Catatan: Karena mekanisme ini didasarkan pada proxy, hanya panggilan metode 'eksternal' yang masuk melalui proxy yang akan dicegat. Ini berarti bahwa 'self-invocation', yaitu metode di dalam objek target yang memanggil beberapa metode lain dari objek target, tidak akan mengarah ke transaksi aktual pada waktu proses meskipun metode yang dipanggil ditandai dengan @Transactional
!
(Penekanan ditambahkan pada kalimat pertama, penekanan lain dari aslinya.)
JdkDynamicAopProxy
melewati semua penasihat kacang pada setiap pemanggilan metode (lihat jugaDefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice()
), yang dalam kasus pengaturan transaksi deklaratif, termasukBeanFactoryTransactionAttributeSourceAdvisor
. Pada gilirannyaTransactionAttributeSourcePointcut#matches()
dipanggil, yang seharusnya mengumpulkan informasi transaksi-relatif. Itu melewati kelas target dan selalu dapat melintasi semua antarmuka yang diimplementasikan kelas ini. Sekarang: mengapa ini tidak dapat bekerja dengan andal?@Transactional
anotasi yang mungkin diwariskan yang akan berlaku? Jadi, meskipun itu semua mungkin , saya tidak menyalahkan Spring. jira.springsource.org/browse/SPR-975Anda dapat meletakkannya di antarmuka tetapi diperingatkan bahwa transaksi mungkin tidak terjadi dalam beberapa kasus. Lihat tip kedua di Secion 10.5.6 dari Spring dokumen:
Saya akan merekomendasikan menempatkan mereka pada implementasi karena alasan ini.
Juga, bagi saya, transaksi tampak seperti detail implementasi sehingga seharusnya ada di kelas implementasi. Bayangkan memiliki implementasi wrapper untuk logging atau implementasi uji (tiruan) yang tidak perlu transaksional.
sumber
Rekomendasi Spring adalah Anda menganotasi implementasi konkret alih-alih antarmuka. Tidak salah menggunakan anotasi pada sebuah antarmuka, itu hanya mungkin untuk menyalahgunakan fitur itu dan secara tidak sengaja mengabaikan deklarasi @Transaction Anda.
Jika Anda telah menandai sesuatu yang transaksional dalam sebuah antarmuka dan kemudian merujuk ke salah satu kelas implementasinya di tempat lain di musim semi, tidak terlalu jelas bahwa objek yang dibuat spring tidak akan menghormati anotasi @Transactional.
Dalam praktiknya terlihat seperti ini:
public class MyClass implements MyInterface { private int x; public void doSomethingNonTx() {} @Transactional public void toSomethingTx() {} }
sumber
Mendukung @Transactional pada kelas beton:
Saya lebih suka merancang solusi dalam 3 bagian secara umum: API, Implementasi, dan Web (jika diperlukan). Saya mencoba yang terbaik untuk menjaga API seringan / sederhana / POJO mungkin dengan meminimalkan ketergantungan. Ini sangat penting jika Anda memainkannya di lingkungan terdistribusi / terintegrasi di mana Anda harus banyak berbagi API.
Menempatkan @Transactional membutuhkan pustaka Spring di bagian API, yang IMHO tidak efektif. Jadi saya lebih suka menambahkannya dalam Implementasi tempat transaksi berjalan.
sumber
Menempatkannya di antarmuka baik-baik saja selama semua pelaksana IFC Anda yang dapat diprediksi peduli tentang data TX (transaksi bukan masalah yang hanya ditangani oleh database). Jika metode tidak peduli tentang TX (tetapi Anda harus meletakkannya di sana untuk Hibernate atau apa pun), letakkan di impl.
Selain itu, mungkin sedikit lebih baik untuk menempatkan
@Transactional
metode di antarmuka:public interface FooService { @Transactional(readOnly = true) void doSmth(); }
sumber