Kita semua tahu perilaku default Hibernate saat menggunakan @SequenceGenerator
- ini meningkatkan urutan database nyata satu , mengalikan nilai ini dengan 50 ( allocationSize
nilai default ) - dan kemudian menggunakan nilai ini sebagai ID entitas.
Ini adalah perilaku yang salah dan bertentangan dengan spesifikasi yang mengatakan:
alokasiSize - (Opsional) Jumlah yang akan ditambahkan saat mengalokasikan nomor urut dari urutan.
Untuk memperjelas: Saya tidak peduli tentang celah antara ID yang dihasilkan.
Saya peduli dengan ID yang tidak konsisten dengan urutan database yang mendasarinya. Misalnya: aplikasi lain (misalnya menggunakan JDBC biasa) mungkin ingin memasukkan baris baru di bawah ID yang diperoleh dari urutan - tetapi semua nilai tersebut mungkin sudah digunakan oleh Hibernate! Kegilaan.
Apakah ada yang tahu solusi untuk masalah ini (tanpa pengaturan allocationSize=1
dan dengan demikian menurunkan kinerja)?
EDIT:
Untuk memperjelas. Jika catatan yang terakhir dimasukkan memiliki ID = 1
, maka nilai penggunaan HB 51, 52, 53...
untuk entitas barunya TETAPI pada saat yang sama: nilai urutan dalam database akan disetel ke 2
. Yang dapat dengan mudah menyebabkan kesalahan saat aplikasi lain menggunakan urutan itu.
Di sisi lain: spesifikasi mengatakan (dalam pemahaman saya) bahwa urutan database seharusnya diatur ke 51
dan sementara itu HB harus menggunakan nilai dari jangkauan 2, 3 ... 50
PEMBARUAN:
Seperti yang disebutkan Steve Ebersole di bawah ini: perilaku yang saya jelaskan (dan juga yang paling intuitif bagi banyak orang) dapat diaktifkan dengan pengaturan hibernate.id.new_generator_mappings=true
.
Terima kasih semuanya.
UPDATE 2:
Untuk pembaca selanjutnya, di bawah ini Anda dapat menemukan contoh yang berfungsi.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_SEQ")
@SequenceGenerator(name = "USERS_SEQ", sequenceName = "SEQUENCE_USERS")
private Long id;
}
persistence.xml
<persistence-unit name="testPU">
<properties>
<property name="hibernate.id.new_generator_mappings" value="true" />
</properties>
</persistence-unit>
save
kebutuhan untuk query database untuk nilai berikutnya dari urutan.SequenceGenerator
Hibernate akan meminta database hanya jika jumlah ID yang ditentukanallocationsize
habis. Jika Anda mengaturallocationSize = 1
maka itu alasan mengapa Hibernate query DB untuk setiap sisipan. Ubah nilai ini, dan Anda selesai.hibernate.id.new_generator_mappings
pengaturan benar-benar penting. Saya berharap ini adalah pengaturan default yang saya tidak perlu menghabiskan begitu banyak waktu untuk meneliti mengapa nomor id menjadi liar.Jawaban:
Untuk lebih jelasnya ... apa yang Anda gambarkan tidak bertentangan dengan spesifikasi sama sekali. Spesifikasi berbicara tentang nilai yang diberikan Hibernate ke entitas Anda, bukan nilai yang sebenarnya disimpan dalam urutan database.
Namun, ada opsi untuk mendapatkan perilaku yang Anda cari. Pertama lihat balasan saya di Apakah ada cara untuk secara dinamis memilih strategi @GeneratedValue menggunakan anotasi JPA dan Hibernate? Itu akan memberi Anda dasar-dasarnya. Selama Anda diatur untuk menggunakan SequenceStyleGenerator itu, Hibernate akan menafsirkan
allocationSize
menggunakan "pengoptimal gabungan" di SequenceStyleGenerator. The "pooled optimizer" adalah untuk digunakan dengan database yang memungkinkan opsi "increment" pada pembuatan urutan (tidak semua database yang mendukung sequence mendukung increment). Bagaimanapun, baca tentang berbagai strategi pengoptimal di sana.sumber
org.hibernate.id.enhanced.SequenceStyleGenerator
. Anda mengejutkan saya.allocationSize=1
Ini adalah optimasi mikro sebelum mendapatkan permintaan Hibernate mencoba untuk menetapkan nilai dalam kisaran alokasiSize dan mencoba untuk menghindari database query untuk urutan. Tetapi query ini akan dieksekusi setiap kali jika Anda mengaturnya ke 1. Ini hampir tidak membuat perbedaan karena jika basis data Anda diakses oleh beberapa aplikasi lain maka akan menimbulkan masalah jika id yang sama digunakan oleh aplikasi lain.Generasi selanjutnya dari Id Urutan didasarkan pada alokasiSize.
Secara defualt disimpan sebagai
50
yang terlalu banyak. Ini juga hanya akan membantu jika Anda akan berada di sekitar50
catatan dalam satu sesi yang tidak dipertahankan dan yang akan dipertahankan menggunakan sesi dan transasi khusus ini.Jadi, Anda harus selalu menggunakan
allocationSize=1
saat menggunakanSequenceGenerator
. Adapun sebagian besar urutan database yang mendasari selalu bertambah1
.sumber
allocationSize=1
Hibernate pada setiapsave
operasi perlu melakukan perjalanan ke database untuk mendapatkan nilai ID baru.allocationSize
dan mencoba untuk menghindari database query untuk urutan. Tetapi kueri ini akan dijalankan setiap kali jika Anda menyetelnya ke 1. Ini hampir tidak membuat perbedaan karena jika basis data Anda diakses oleh beberapa aplikasi lain maka akan menimbulkan masalah jika id yang sama digunakan oleh aplikasi lain sementara ituSteve Ebersole & anggota lain,
Maukah Anda menjelaskan alasan id dengan celah yang lebih besar (secara default 50)? Saya menggunakan Hibernate 4.2.15 dan menemukan kode berikut di org.hibernate.id.enhanced.OptimizerFactory cass.
Setiap kali itu mengenai bagian dalam pernyataan if, nilai hi menjadi jauh lebih besar. Jadi, id saya selama pengujian dengan server yang sering restart menghasilkan id urutan berikut:
1, 2, 3, 4, 19, 250, 251, 252, 400, 550, 750, 751, 752, 850, 1100, 1150.
Saya tahu Anda sudah mengatakan itu tidak bertentangan dengan spesifikasi, tetapi saya yakin ini akan menjadi situasi yang sangat tidak terduga bagi sebagian besar pengembang.
Masukan siapa pun akan sangat membantu.
Jihwan
UPDATE: ne1410s: Terima kasih atas pengeditannya.
cfrick: Oke. Saya akan melakukan itu. Itu adalah posting pertama saya di sini dan tidak yakin bagaimana cara menggunakannya.
Sekarang, saya lebih mengerti mengapa maxLo digunakan untuk dua tujuan: Karena hibernate memanggil urutan DB sekali, terus tingkatkan id di level Java, dan simpan ke DB, nilai id level Java harus mempertimbangkan berapa banyak yang berubah tanpa memanggil urutan DB ketika memanggil urutan waktu berikutnya.
Misalnya, id urutan adalah 1 pada satu titik dan hibernasi memasuki 5, 6, 7, 8, 9 (dengan alokasiSize = 5). Lain kali, ketika kita mendapatkan nomor urut berikutnya, DB mengembalikan 2, tetapi hibernasi perlu menggunakan 10, 11, 12 ... Jadi, itulah mengapa "hi = lastSourceValue.copy (). MultiplyBy (maxLo + 1)" adalah digunakan untuk mendapatkan id 10 berikutnya dari 2 yang dikembalikan dari urutan DB. Tampaknya hanya hal yang mengganggu adalah selama server restart sering dan ini adalah masalah saya dengan celah yang lebih besar.
Jadi, ketika kita menggunakan ID SEQUENCE, id yang dimasukkan di tabel tidak akan cocok dengan nomor SEQUENCE di DB.
sumber
Setelah menggali kode sumber hibernasi dan konfigurasi Di bawah ini, buka Oracle db untuk nilai berikutnya setelah 50 penyisipan. Jadi, buat kenaikan INST_PK_SEQ Anda menjadi 50 setiap kali dipanggil.
Hibernate 5 digunakan untuk strategi di bawah ini
Periksa juga di bawah ini http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence
sumber
allocationSize
maupuninitialValue
secara global untuk semua entitas (kecuali hanya menggunakan satu generator, tetapi IMHO itu tidak terlalu mudah dibaca).Saya juga menghadapi masalah ini di Hibernate 5:
Dapatkan peringatan seperti ini di bawah ini:
Kemudian ubah kode saya menjadi SequenceStyleGenerator:
Ini memecahkan dua masalah saya:
sumber
Saya akan memeriksa DDL untuk urutan dalam skema. Implementasi JPA hanya bertanggung jawab atas pembuatan urutan dengan ukuran alokasi yang benar. Oleh karena itu, jika ukuran alokasinya adalah 50 maka urutan Anda harus memiliki kenaikan 50 di DDL-nya.
Kasus ini biasanya dapat terjadi dengan pembuatan urutan dengan ukuran alokasi 1 yang kemudian dikonfigurasi ke ukuran alokasi 50 (atau default) tetapi urutan DDL tidak diperbarui.
sumber
ALTER SEQUENCE ... INCREMENTY BY 50;
tidak akan menyelesaikan apa pun, karena masalahnya masih tetap sama. Nilai urutan masih tidak mencerminkan ID entitas yang sebenarnya.