Saya baru mengenal Transaksi Musim Semi. Sesuatu yang menurut saya sangat aneh, mungkin saya memahami ini dengan benar.
Saya ingin melakukan transaksi di sekitar level metode dan saya memiliki metode pemanggil dalam kelas yang sama dan sepertinya tidak seperti itu, itu harus dipanggil dari kelas yang terpisah. Saya tidak mengerti bagaimana itu mungkin.
Jika ada yang punya ide bagaimana menyelesaikan masalah ini, saya akan sangat menghargai. Saya ingin menggunakan kelas yang sama untuk memanggil metode transaksional beranotasi.
Ini kodenya:
public class UserService {
@Transactional
public boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
public boolean addUsers(List<User> users) {
for (User user : users) {
addUser(user.getUserName, user.getPassword);
}
}
}
java
spring
aspectj
spring-aop
Mike
sumber
sumber
TransactionTemplate
pendekatannya: stackoverflow.com/a/52989925/355438Jawaban:
Ini adalah batasan Spring AOP (objek dinamis dan cglib ).
Jika Anda mengonfigurasi Spring untuk menggunakan AspectJ untuk menangani transaksi, kode Anda akan berfungsi.
Alternatif sederhana dan mungkin terbaik adalah dengan memfaktor ulang kode Anda. Misalnya satu kelas yang menangani pengguna dan satu lagi yang memproses setiap pengguna. Kemudian penanganan transaksi default dengan Spring AOP akan berfungsi.
Tip konfigurasi untuk menangani transaksi dengan AspectJ
Untuk mengaktifkan Spring menggunakan AspectJ untuk transaksi, Anda harus mengatur mode ke AspectJ:
Jika Anda menggunakan Spring dengan versi yang lebih lama dari 3.0, Anda juga harus menambahkan ini ke konfigurasi Spring Anda:
sumber
Masalahnya di sini adalah, bahwa proxy AOP Spring tidak memperluas melainkan membungkus instance layanan Anda untuk mencegat panggilan. Ini berdampak, bahwa setiap panggilan ke "ini" dari dalam instance layanan Anda secara langsung dipanggil pada instance itu dan tidak dapat dicegat oleh proxy pembungkus (proxy bahkan tidak mengetahui panggilan semacam itu). Salah satu solusi telah disebutkan. Cara bagus lainnya adalah dengan meminta Spring menyuntikkan instance layanan ke dalam layanan itu sendiri, dan memanggil metode Anda pada instance yang diinjeksi, yang akan menjadi proxy yang menangani transaksi Anda. Tetapi ketahuilah, bahwa ini mungkin memiliki efek samping yang buruk juga, jika kacang layanan Anda bukan tunggal:
sumber
UserService
memiliki cakupan tunggal? Bagaimana jika itu adalah objek yang sama?Dengan Spring 4 dimungkinkan untuk Self autowired
sumber
Mulai dari Java 8 ada kemungkinan lain, yang saya lebih suka karena alasan yang diberikan di bawah ini:
Pendekatan ini memiliki keuntungan sebagai berikut:
1) Ini dapat diterapkan pada metode pribadi . Jadi Anda tidak perlu merusak enkapsulasi dengan membuat metode menjadi publik hanya untuk memenuhi batasan Spring.
2) Metode yang sama dapat dipanggil dalam propagasi transaksi yang berbeda dan terserah pemanggil untuk memilih yang sesuai. Bandingkan 2 baris ini:
3) Ini eksplisit, sehingga lebih mudah dibaca.
sumber
TransactionHandler
sebagai subkelas, dan subkelas tersebut memanggil dua metode ini diTransactionHandler
kelas super, apakah saya masih bisa mendapatkan manfaat@Transactional
seperti yang dimaksudkan?Ini adalah solusi saya untuk doa sendiri :
sumber
Anda dapat membuat BeanFactory secara otomatis di dalam kelas yang sama dan melakukan
getBean(YourClazz.class)
Ini akan secara otomatis memproksifikasi kelas Anda dan memperhitungkan @Transactional atau anotasi aop Anda lainnya.
sumber
Masalahnya terkait dengan bagaimana kelas dan proxy beban pegas. Ini tidak akan berfungsi, sampai Anda menulis metode / transaksi batin Anda di kelas lain atau pergi ke kelas lain dan kemudian kembali lagi ke kelas Anda dan kemudian menulis metode transkasi bersarang bagian dalam.
Untuk meringkas, proxy pegas tidak mengizinkan skenario yang Anda hadapi. Anda harus menulis metode transaksi ke-2 di kelas lain
sumber
Inilah yang saya lakukan untuk proyek kecil dengan hanya penggunaan marginal dari pemanggilan metode dalam kelas yang sama. Dokumentasi dalam kode sangat disarankan, karena mungkin terlihat aneh bagi rekan kerja. Namun, alat ini bekerja dengan lajang , mudah diuji, sederhana, cepat dicapai, dan menghemat instrumentasi AspectJ sepenuhnya. Namun, untuk penggunaan yang lebih berat, saya akan menyarankan solusi AspectJ seperti yang dijelaskan dalam jawaban Espens.
sumber