Saya ingin tahu apa yang sebenarnya terjadi ketika Anda menjelaskan metode dengan @Transactional
? Tentu saja, saya tahu Spring akan membungkus metode itu dalam suatu Transaksi.
Tapi, saya memiliki keraguan sebagai berikut:
- Saya mendengar bahwa Spring membuat kelas proxy ? Dapatkah seseorang menjelaskan hal ini secara lebih mendalam . Apa yang sebenarnya berada di kelas proxy itu? Apa yang terjadi pada kelas aktual? Dan bagaimana saya bisa melihat kelas proksi yang dibuat Spring
- Saya juga membaca dalam dokumen Spring bahwa:
Catatan: Karena mekanisme ini didasarkan pada proksi, hanya panggilan metode 'eksternal' yang masuk melalui proxy yang akan disadap . Ini berarti bahwa 'invokasi diri', yaitu suatu metode di dalam objek target yang memanggil beberapa metode lain dari objek target, tidak akan mengarah pada transaksi aktual saat runtime bahkan jika metode yang dipanggil ditandai dengan
@Transactional
!
Sumber: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Mengapa hanya panggilan metode eksternal yang berada di bawah Transaksi dan bukan metode doa mandiri?
Jawaban:
Ini adalah topik besar. Dokumen referensi Spring mencurahkan banyak bab untuk itu. Saya sarankan membaca yang pada Pemrograman Berorientasi Aspek dan Transaksi , karena dukungan transaksi deklaratif Spring menggunakan AOP di yayasannya.
Tetapi pada level yang sangat tinggi, Spring menciptakan proksi untuk kelas yang menyatakan @Transaksional pada kelas itu sendiri atau pada anggota. Proxy sebagian besar tidak terlihat saat runtime. Ini memberikan cara bagi Spring untuk menyuntikkan perilaku sebelum, setelah, atau sekitar pemanggilan metode ke objek yang sedang diproksikan. Manajemen transaksi hanyalah salah satu contoh perilaku yang dapat dihubungkan. Pemeriksaan keamanan adalah hal lain. Dan Anda juga bisa menyediakan sendiri untuk hal-hal seperti logging. Jadi, ketika Anda membubuhi keterangan metode dengan @Transaksional , Spring secara dinamis membuat proksi yang mengimplementasikan antarmuka yang sama dengan kelas yang Anda beri penjelasan. Dan ketika klien melakukan panggilan ke objek Anda, panggilan dicegat dan perilaku disuntikkan melalui mekanisme proxy.
Transaksi di EJB bekerja dengan cara yang sama.
Seperti yang Anda amati, melalui, mekanisme proksi hanya berfungsi ketika panggilan masuk dari beberapa objek eksternal. Saat Anda membuat panggilan internal di dalam objek, Anda benar-benar melakukan panggilan melalui referensi " ini ", yang melewati proxy. Namun, ada beberapa cara untuk mengatasi masalah itu. Saya menjelaskan satu pendekatan dalam posting forum ini di mana saya menggunakan BeanFactoryPostProcessor untuk menyuntikkan instance dari proxy ke kelas "referensi diri" pada saat runtime. Saya menyimpan referensi ini ke variabel anggota yang disebut " saya ". Kemudian jika saya perlu membuat panggilan internal yang memerlukan perubahan dalam status transaksi utas, saya mengarahkan panggilan melalui proxy (mis. " Me.someMethod ()".) Posting forum menjelaskan lebih detail. Perhatikan bahwa BeanFactoryPostProcessorkode akan sedikit berbeda sekarang, seperti yang ditulis kembali dalam jangka waktu Musim Semi 1.x. Tapi mudah-mudahan ini memberi Anda ide. Saya memiliki versi terbaru yang mungkin bisa saya sediakan.
sumber
BeanFactoryPostProcessor
. Namun, ada (menurut saya) metode yang sangat mirip yang dijelaskan dalam jawaban ini: stackoverflow.com/a/11277899/3667003 ... dan solusi lebih lanjut di seluruh utas juga.Ketika Spring memuat definisi kacang Anda, dan telah dikonfigurasi untuk mencari
@Transactional
anotasi, itu akan membuat objek proxy ini di sekitar kacang Anda yang sebenarnya . Objek proxy ini adalah instance dari kelas yang dihasilkan secara otomatis saat runtime. Perilaku default objek-objek proxy ini ketika sebuah metode dipanggil hanya untuk memanggil metode yang sama pada kacang "target" (yaitu kacang Anda).Namun, proksi juga dapat diberikan dengan pencegat, dan saat ini pencegat ini akan dipanggil oleh proxy sebelum memanggil metode target bean Anda. Untuk kacang target yang dijelaskan dengan
@Transactional
, Spring akan membuatTransactionInterceptor
, dan meneruskannya ke objek proxy yang dihasilkan. Jadi ketika Anda memanggil metode dari kode klien, Anda memanggil metode pada objek proxy, yang pertama kali memanggilTransactionInterceptor
(yang memulai transaksi), yang pada gilirannya memanggil metode pada kacang target Anda. Ketika doa selesai,TransactionInterceptor
komit / memutar kembali transaksi. Ini transparan untuk kode klien.Adapun hal "metode eksternal", jika kacang Anda memanggil salah satu metodenya sendiri, maka kacang itu tidak akan melakukannya melalui proxy. Ingat, Spring membungkus kacang Anda di proxy, kacang Anda tidak memiliki pengetahuan tentang itu. Hanya panggilan dari "luar" kacang Anda melalui proxy.
Apakah itu membantu?
sumber
Sebagai orang visual, saya suka menimbang dengan diagram urutan pola proxy. Jika Anda tidak tahu cara membaca panah, saya membaca yang pertama seperti ini:
Client
dijalankanProxy.method()
.(Saya diizinkan memposting foto dengan syarat saya menyebutkan asal-usulnya. Penulis: Noel Vaes, situs web: www.noelvaes.eu)
sumber
Jawaban paling sederhana adalah:
Pada metode mana pun Anda menyatakan
@Transactional
batas transaksi dimulai dan batas berakhir ketika metode selesai.Jika Anda menggunakan panggilan JPA maka semua komit ada dalam batas transaksi ini .
Katakanlah Anda menyimpan entitas1, entitas2 dan entitas3. Sekarang saat menyimpan entitas3 pengecualian terjadi , maka sebagai enitiy1 dan entitas2 datang dalam transaksi yang sama sehingga entitas1 dan entitas2 akan rollback dengan entitas3.
Transaksi :
Pengecualian akan menghasilkan kemunduran semua transaksi JPA dengan DB. Secara internal transaksi JPA digunakan oleh Spring.
sumber
Mungkin terlambat tapi saya menemukan sesuatu yang menjelaskan kekhawatiran Anda terkait dengan proxy (hanya panggilan metode 'eksternal' yang masuk melalui proxy yang akan dicegat) dengan baik.
Misalnya, Anda memiliki kelas yang terlihat seperti ini
dan Anda memiliki aspek, yang terlihat seperti ini:
Ketika Anda menjalankannya seperti ini:
}
Hasil pemanggilan kickOff di atas diberikan kode di atas.
tetapi ketika Anda mengubah kode Anda ke
Anda lihat, metode ini memanggil metode lain secara internal sehingga tidak akan dicegat dan hasilnya akan terlihat seperti ini:
Anda dapat melewati ini dengan melakukan itu
Cuplikan kode diambil dari: https://www.intertech.com/Blog/secrets-of-the-spring-aop-proxy/
sumber
Semua jawaban yang ada benar, tetapi saya merasa tidak bisa memberikan topik yang kompleks ini.
Untuk penjelasan praktis dan komprehensif, Anda mungkin ingin melihat pada panduan Kedalaman Transaksional Spring @Transactional ini , yang mencoba yang terbaik untuk membahas manajemen transaksi dalam ~ 4000 kata sederhana, dengan banyak contoh kode.
sumber