Karena kebuntuan sering terjadi, sepertinya beberapa utas aplikasi menahan kunci untuk waktu yang lama.
Setiap utas dalam aplikasi akan menggunakan koneksi/koneksi basis datanya sendiri saat mengakses basis data, jadi dari sudut pandang basis data, dua utas adalah dua klien berbeda yang bersaing untuk kunci basis data.
Jika utas menahan kunci untuk jangka waktu yang lama dan memperolehnya dalam urutan tertentu, dan utas kedua datang dengan memperoleh kunci yang sama tetapi pada urutan yang berbeda, kebuntuan pasti akan terjadi (lihat di sini untuk detail tentang penyebab kebuntuan yang sering terjadi ini).
Juga terjadi kebuntuan dalam operasi baca, yang berarti bahwa beberapa utas juga memperoleh kunci baca. Ini terjadi jika utas menjalankan transaksi di REPEATABLE_READ
tingkat isolasi atau SERIALIZABLE
.
Untuk mengatasinya, coba cari penggunaan Isolation.REPEATABLE_READ
dan Isolation.SERIALIZABLE
dalam proyek, untuk melihat apakah ini sedang digunakan.
Sebagai alternatif, gunakan READ_COMMITTED
default tingkat isolasi dan beri anotasi pada entitas dengan @Version
, untuk menangani konkurensi menggunakan penguncian optimis
sebagai gantinya.
Coba juga identifikasi transaksi yang berjalan lama, hal ini terkadang terjadi saat @Transactional
ditempatkan di tempat yang salah dan membungkus misalnya pemrosesan seluruh file dalam contoh pemrosesan batch, alih-alih melakukan transaksi baris demi baris.
Ini konfigurasi log4j untuk mencatat pembuatan/penghapusan manajer entitas dan transaksi dimulai/komit/kembalikan:
<!-- spring entity manager and transactions -->
<logger name="org.springframework.orm.jpa" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
<logger name="org.springframework.transaction" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
- Dapatkah saya menjalankan kueri pembaruan (baik JPA/Native) tanpa harus mengunci tabel melalui @Transactional?
Kueri pembaruan dimungkinkan melalui kueri asli atau JPQL .
- Bisakah saya masuk ke sesi tanpa menggunakan @Transactional? Misalnya, utas terjadwal mencoba membaca bidang Malas pada Entitas menghasilkan LazyInitializationException - tidak ada sesi, jika metode tidak dianotasi dengan @Transactional
Dalam metode tanpa @Transactional
, kueri akan dieksekusi di pengelola entitasnya sendiri dan hanya mengembalikan entitas yang terlepas, karena sesi ditutup segera setelah kueri dijalankan.
jadi pengecualian inisialisasi malas dalam metode tanpa @Transactional
adalah normal. Anda dapat mengaturnya ke @Transactional(readOnly=true)
juga.