Bagaimana cara @Version
kerja anotasi di JPA?
Saya menemukan berbagai jawaban yang ekstraknya adalah sebagai berikut:
JPA menggunakan kolom versi di entitas Anda untuk mendeteksi modifikasi serentak ke data datastore yang sama. Ketika runtime JPA mendeteksi upaya untuk mengubah rekaman yang sama secara bersamaan, itu membuat pengecualian ke transaksi yang mencoba untuk melakukan terakhir.
Tapi saya masih belum yakin bagaimana cara kerjanya.
Juga seperti dari baris berikut:
Anda harus menganggap bidang versi tidak dapat diubah. Mengubah nilai bidang memiliki hasil yang tidak ditentukan.
Apakah ini berarti bahwa kita harus mendeklarasikan field versi kita sebagai final
?
java
jpa
jpa-annotations
Yatendra Goel
sumber
sumber
UPDATE myentity SET mycolumn = 'new value', version = version + 1 WHERE version = [old.version]
. Jika seseorang memperbarui catatan,old.version
tidak akan lagi cocok dengan yang ada di DB dan klausul where akan mencegah pembaruan terjadi. 'Baris yang diperbarui' akan menjadi0
, yang dapat dideteksi JPA untuk menyimpulkan bahwa modifikasi bersamaan terjadi.Jawaban:
Misalkan sebuah entitas
MyEntity
memilikiversion
properti beranotasi :Saat diperbarui, bidang yang dianotasi
@Version
akan bertambah dan ditambahkan keWHERE
klausa, seperti ini:Jika
WHERE
klausa gagal untuk mencocokkan rekaman (karena entitas yang sama telah diperbarui oleh utas lain), penyedia persistensi akan melemparOptimisticLockException
.Tidak, tetapi Anda dapat mempertimbangkan untuk membuat setter dilindungi karena Anda tidak seharusnya menyebutnya.
sumber
long
atau hanya memanggilnyalongValue()
. Anda membutuhkannull
pemeriksaan eksplisit . Saya tidak akan melakukan inisialisasi secara eksplisit karena kolom ini seharusnya dikelola oleh penyedia ORM. Saya pikir ini akan diatur untuk0L
pertama kali dimasukkan ke dalam DB, jadi jika diatur kenull
ini memberitahu Anda bahwa catatan ini belum disimpan.Long
daripada primitiflong
untuk@Version
bidang tersebut, karenaSimpleJpaRepository.save(entity)
kemungkinan akan memperlakukan bidang versi null sebagai indikator bahwa entitas tersebut baru. Jika entitas tersebut baru (seperti yang ditunjukkan oleh versi menjadi null), Spring akan memanggilem.persist(entity)
. Tetapi jika versi memiliki nilai, maka itu akan memanggilem.merge(entity)
. Ini juga alasan mengapa bidang versi yang dideklarasikan sebagai jenis pembungkus harus dibiarkan tidak diinisialisasi.Meskipun jawaban @Pascal benar-benar valid, dari pengalaman saya, saya menemukan kode di bawah ini membantu untuk mencapai penguncian yang optimis:
Mengapa? Karena:
@Version
disetel ke tidak sengajanull
.optlock
daripadaversion
.Titik pertama tidak masalah jika menggunakan aplikasi hanya JPA untuk memasukkan data ke dalam database, sebagai vendor JPA akan menegakkan
0
untuk@version
bidang pada waktu penciptaan. Tetapi hampir selalu pernyataan SQL biasa juga digunakan (setidaknya selama pengujian unit dan integrasi).sumber
u_lmod
(pengguna terakhir diubah) di mana pengguna dapat menjadi manusia atau didefinisikan (otomatis) proses / entitas / aplikasi (jadi menyimpan jugau_lmod_id
bisa masuk akal). (Menurut saya, atribut-meta-bisnis yang sangat mendasar). Ini biasanya menyimpan nilainya sebagai DATE (TIME) (artinya info tentang tahun ... milidetik) dalam UTC (jika "lokasi" zona waktu dari editor penting untuk disimpan kemudian dengan zona waktu). juga sangat berguna untuk skenario sinkronisasi DWH.Setiap kali entitas diperbarui dalam database, bidang versi akan bertambah satu. Setiap operasi yang memperbarui entitas dalam database akan ditambahkan
WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASE
ke kuerinya.Dalam memeriksa baris yang terpengaruh dari operasi Anda, kerangka kerja jpa dapat memastikan tidak ada modifikasi bersamaan antara memuat dan mempertahankan entitas Anda karena kueri tidak akan menemukan entitas Anda dalam database ketika nomor versinya telah ditingkatkan antara memuat dan bertahan.
sumber
Versi digunakan untuk memastikan bahwa hanya satu pembaruan dalam satu waktu. Penyedia JPA akan memeriksa versinya, jika versi yang diharapkan sudah meningkat maka orang lain sudah memperbarui entitas sehingga pengecualian akan dilempar.
Jadi memperbarui nilai entitas akan lebih aman, lebih optimis.
Jika nilai sering berubah, maka Anda mungkin mempertimbangkan untuk tidak menggunakan kolom versi. Sebagai contoh "entitas yang memiliki kolom tandingan, yang akan meningkat setiap kali halaman web diakses"
sumber
Hanya menambahkan sedikit info lagi.
JPA mengelola versi di bawah tenda untuk Anda, namun JPA tidak melakukannya saat Anda memperbarui data melalui
JPAUpdateClause
, dalam kasus seperti itu Anda perlu menambahkan kenaikan versi secara manual ke kueri.Hal yang sama dapat dikatakan tentang memperbarui melalui JPQL, yaitu bukan perubahan sederhana ke entitas, tetapi perintah pembaruan ke database meskipun itu dilakukan dengan hibernate
Pedro
sumber
JPAUpdateClause
?