Hazırda bekletme, @SequenceGenerator ve ayırmaSize


117

Kullanırken Hepimiz hazırda varsayılan davranışını bilmek @SequenceGenerator- bu gerçek veritabanı dizisi arttırır biri 50 (varsayılan tarafından, birden bu değeri allocationSizedeğeri) - ve sonra varlık kimliği olarak bu değeri kullanır.

Bu yanlış bir davranıştır ve şunu söyleyen spesifikasyonla çelişir :

tahsisat boyutu - (İsteğe bağlı) Sıradan sıra numaraları tahsis edilirken artırılacak miktar.

Açık olmak gerekirse: Oluşturulan kimlikler arasındaki boşluklardan rahatsız değilim.

Temel veritabanı sırasına uymayan kimlikleri önemsiyorum . Örneğin: başka herhangi bir uygulama (örneğin, düz JDBC kullanan), diziden elde edilen kimliklerin altına yeni satırlar eklemek isteyebilir - ancak tüm bu değerler zaten Hazırda Bekletme tarafından kullanılıyor olabilir! Delilik.

Birisi bu soruna herhangi bir çözüm biliyor allocationSize=1mu (performansı ayarlamadan ve dolayısıyla performansı düşürmeden)?

DÜZENLEME:
Her şeyi netleştirmek için. Son eklenen kayıtta ID = varsa 1, HB 51, 52, 53...yeni varlıkları için değerleri kullanır AMA aynı zamanda: dizinin veritabanındaki değeri olarak ayarlanacaktır 2. Diğer uygulamalar bu sırayı kullanırken kolayca hatalara yol açabilir.

Diğer taraftan: spesifikasyon, (benim anlayışıma göre) veritabanı sırasının ayarlanması gerektiğini 51ve bu arada HB'nin aralıktaki değerleri kullanması gerektiğini söylüyor.2, 3 ... 50


GÜNCELLEME:
Steve Ebersole'un aşağıda belirtildiği gibi: benim tarafımdan açıklanan davranış (ve aynı zamanda çoğu için en sezgisel olanı) ayarlanarak etkinleştirilebilir hibernate.id.new_generator_mappings=true.

Hepinize teşekkürler.

GÜNCELLEME 2:
Gelecekteki okuyucular için, aşağıda çalışan bir örnek bulabilirsiniz.

@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>

2
"assignationSize = 1'i ayarlamadan ve dolayısıyla performansı düşürmeden" performansı neden 1 olarak ayarladınız?
sheidaei

3
@sheidaei bakınız aşağıdaki açıklama olabilir :-) Bunun nedeni, herkesin savesıranın bir sonraki değeri için veritabanını sorgulaması gerektiğidir.
G. Demecki

Teşekkürler aynı sorunla karşı karşıyaydınız. İlk başta her @SequenceGenerator'a ayırmaSize = 1 ekliyordum. Hibernate.id.new_generator_mappings = true kullanılması bunu engelleyin. JPA hala her giriş için kimliği almak için veritabanını
sorgulasa da

1
SequenceGeneratorHibernate ile yalnızca tarafından belirtilen kimlik sayısı bittiğinde veritabanını sorgular allocationsize. Eğer kurarsanız allocationSize = 1o zaman nedeni hazırda sorgusu DB her ekleme için. Bu değeri değiştirin ve bitirdiniz.
G. Demecki

1
Teşekkürler! hibernate.id.new_generator_mappingsAyar gerçekten önemli. Umarım bu, kimlik numarasının neden vahşi gittiğini araştırmak için çok fazla zaman harcamak zorunda kalmamamın varsayılan ayardır.
LeOn - Han Li

Yanıtlar:


43

Kesinlikle açık olmak gerekirse ... açıkladığınız yapar değil herhangi bir şekilde spec ile çatışma. Spesifikasyon, Hibernate'in varlıklarınıza atadığı değerlerden bahsediyor, veritabanı dizisinde gerçekte depolanan değerlerden değil.

Bununla birlikte, aradığınız davranışı elde etme seçeneği vardır. İlk olarak yanıtımı görün: JPA ek açıklamalarını ve Hazırda Bekletme'yi kullanarak @GeneratedValue stratejisini dinamik olarak seçmenin bir yolu var mı? Bu size temel bilgileri verecektir. Bu SequenceStyleGenerator'ı kullanmak üzere ayarlandığınız sürece, Hibernate, SequenceStyleGenerator'daki allocationSize"havuzlanmış iyileştirici" yi kullanarak yorumlayacaktır . "Havuzlanmış iyileştirici", dizilerin oluşturulmasında bir "artış" seçeneğine izin veren veritabanlarıyla kullanım içindir (dizileri destekleyen tüm veritabanları bir artışı desteklemez). Her neyse, oradaki çeşitli optimize edici stratejileri hakkında bilgi edinin.


Teşekkürler Steve! En iyi cevap. Diğer gönderiniz de yardımcı oldu.
G. Demecki

4
Ayrıca ortak yazar olduğunuzu da fark ettim org.hibernate.id.enhanced.SequenceStyleGenerator. Beni şaşırttın.
G. Demecki

22
Nasıl şaşırttı? Hibernate'in baş geliştiricisiyim. Birçok Hibernate sınıfı yazdım / yazdım;)
Steve Ebersole

Sadece kayıt için. Büyük boşlukları önlemek için DB dizisi Artışından kaçınılmalıdır. Kimlik önbelleği bittiğinde DB dizisi ayırma boyutu ile çarpılır.Daha fazla ayrıntı stackoverflow.com/questions/5346147/…
Olcay Tarazan

1
Genel olarak kullanılan "iyileştiriciyi" değiştirmenin bir yolu, hazırda bekletme seçeneklerinize buna benzer bir şey eklemektir: serviceBuilder.applySetting ("hibernate.id.optimizer.pooled.preferred", LegacyHiLoAlgorithmOptimizer.class.getName ()); LegacyHiLoAlgorithOptimizer yerine herhangi bir optimize edici sınıf seçebilirsiniz ve bu sınıf varsayılan olacaktır. Bu, tüm ek açıklamaları değiştirmeden varsayılan olarak istediğiniz davranışı korumayı kolaylaştırmalıdır. Ek olarak, "havuzlanmış" ve "hilo" optimize edicilerine dikkat edin: bunlar, sıra değeriniz 0'dan başlayıp negatif kimliklere neden olduğunda garip sonuçlar verir.
fjalvingh

17

allocationSize=1Bu, sorguyu almadan önce yapılan bir mikro optimizasyondur. Hibernate, ayırmaSize aralığında değer atamaya çalışır ve bu nedenle, veritabanı dizisini sorgulamaktan kaçınmaya çalışır. Ancak, 1'e ayarlarsanız bu sorgu her seferinde yürütülecektir. Bu, veri tabanınıza başka bir uygulama tarafından erişilirse, aynı kimlik bu arada başka bir uygulama tarafından kullanılırsa sorun yaratacağından, bu neredeyse hiç fark etmez.

Yeni nesil Sıra Kimliği, tahsisat boyutuna bağlıdır.

Varsayılan olarak 50, çok fazla olanı olarak tutulur . Aynı zamanda, sadece 50bir oturumda, kalıcı olmayan ve bu belirli oturum ve çeviri kullanılarak kalıcı olacak kayıtlara yakın olacaksanız yardımcı olacaktır.

Böylece her zaman kullanmalısınız allocationSize=1kullanırken SequenceGenerator. Temel veri tabanlarının çoğunda olduğu gibi, dizi her zaman artırılır 1.


12
Performansla ilgisi yok mu? Eğer misiniz gerçekten emin? allocationSize=1Her saveoperasyonda Hibernate ile yeni ID değeri elde etmek için veri tabanına yolculuk yapması gerektiği öğretildi .
G. Demecki

2
Hibernate sorguyu almadan önce mikro optimizasyondur allocationSizeve bu nedenle sırayla veritabanını sorgulamaktan kaçınmaya çalışır. Ancak bu sorgu, 1'e ayarlarsanız her seferinde yürütülecektir. Bu neredeyse hiç fark etmez, çünkü veri tabanınıza başka bir uygulama tarafından erişilirse, aynı kimlik başka bir uygulama tarafından kullanılırsa sorun yaratacaktır
Amit Deshpande,

Ve evet, 1 tahsis büyüklüğünün herhangi bir gerçek performans etkisinin olup olmadığı tamamen uygulamaya özeldir. Elbette bir mikro ölçütte, her zaman büyük bir etki olarak ortaya çıkacaktır; Çoğu kıyaslamadaki problem budur (mikro veya başka türlü), basitçe gerçekçi değillerdir. Biraz gerçekçi olacak kadar karmaşık olsalar bile, karşılaştırma sonuçlarının uygulamanızda göreceğiniz sonuçlara ne kadar uygun olduğunu anlamak için karşılaştırmanın gerçek uygulamanıza ne kadar yakın olduğuna yine de bakmanız gerekir. Uzun lafın kısası .. kendin için
dene

2
TAMAM. Her şey uygulamaya özel, öyle değil mi! Uygulamanız salt okunur bir uygulama ise, 1000 veya 1 ayırma boyutunu kullanmanın etkisi kesinlikle 0'dır. Öte yandan, bunlar gibi şeyler en iyi uygulamalardır. Topladıkları en iyi uygulamalara saygı göstermezseniz ve birleşik etki, uygulamanızın yavaşlaması olacaktır. Başka bir örnek, kesinlikle ihtiyacınız olmadığında bir işleme başlamaktır.
Hasan Ceylan

1

Steve Ebersole ve diğer üyeler,
Daha büyük bir boşluğa (varsayılan olarak 50) sahip bir kimliğin nedenini açıklar mısınız? Hibernate 4.2.15 kullanıyorum ve aşağıdaki kodu org.hibernate.id.enhanced.OptimizerFactory cass içinde buldum.

if ( lo > maxLo ) {
   lastSourceValue = callback.getNextValue();
   lo = lastSourceValue.eq( 0 ) ? 1 : 0;
   hi = lastSourceValue.copy().multiplyBy( maxLo+1 ); 
}  
value = hi.copy().add( lo++ );

Ne zaman if ifadesinin içine girse, hi değeri çok daha büyük hale geliyor. Bu nedenle, sık sık sunucu yeniden başlatma ile test sırasında kimliğim şu sıra kimliklerini oluşturur:
1, 2, 3, 4, 19, 250, 251, 252, 400, 550, 750, 751, 752, 850, 1100, 1150.

Teknik özelliklerle çelişmediğini zaten söylediğini biliyorum, ancak bunun çoğu geliştirici için çok beklenmedik bir durum olacağına inanıyorum.

Herhangi birinin girdisi çok yardımcı olacaktır.

Jihwan

GÜNCELLEME: ne1410s: Düzenleme için teşekkürler.
cfrick: Tamam. Yapacağım. Buradaki ilk yazımdı ve nasıl kullanılacağından emin değildim.

Şimdi, maxLo'nun neden iki amaç için kullanıldığını daha iyi anladım: Hazırda bekletme, DB dizisini bir kez çağırdığından, Java düzeyinde kimliği artırmaya devam et ve bunu DB'ye kaydettiğinden, Java düzeyi kimlik değeri, çağrı yapılmadan ne kadar değiştirildiğini dikkate almalıdır. Bir dahaki sefere sırayı çağırdığında DB dizisi.

Örneğin, sıra kimliği bir noktada 1 idi ve hazırda bekletme 5, 6, 7, 8, 9'a girdi (ayırmaSize = 5 ile). Bir dahaki sefere, bir sonraki sıra numarasını aldığımızda, DB 2 döndürür, ancak hazırda bekletme için 10, 11, 12 ... kullanılması gerekir. Bu nedenle, "hi = lastSourceValue.copy (). MultiplyBy (maxLo + 1)" DB dizisinden dönen 2'den sonraki id 10'u almak için kullanılır. Görünüşe göre sadece rahatsız edici bir şey sunucunun sık sık yeniden başlatılması sırasında oldu ve bu daha büyük boşlukla ilgili sorunumdu.

Dolayısıyla, SEQUENCE ID'yi kullandığımızda, tabloya eklenen id, DB'deki SEQUENCE numarasıyla eşleşmeyecektir.


1

Hazırda bekletme kaynak kodunu kazdıktan sonra ve Aşağıdaki yapılandırma 50 eklemeden sonra sonraki değer için Oracle db'ye gider. Bu nedenle, INST_PK_SEQ'nuzu her çağrıldığında 50 artırın.

Hibernate 5 aşağıdaki strateji için kullanılır

Ayrıca http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence adresini de kontrol edin

@Id
@Column(name = "ID")
@GenericGenerator(name = "INST_PK_SEQ", 
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
        @org.hibernate.annotations.Parameter(
                name = "optimizer", value = "pooled-lo"),
        @org.hibernate.annotations.Parameter(
                name = "initial_value", value = "1"),
        @org.hibernate.annotations.Parameter(
                name = "increment_size", value = "50"),
        @org.hibernate.annotations.Parameter(
                name = SequenceStyleGenerator.SEQUENCE_PARAM, value = "INST_PK_SEQ"),
    }
)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "INST_PK_SEQ")
private Long id;

3
Üzgünüz, ama bu, bir şeyler kurmanın son derece ayrıntılı bir yoludur ve bu, bütün bir Hazırda Bekletme ve dolayısıyla tüm varlıklar için iki parametre ile kolayca ifade edilebilir.
G. Demecki

doğru ama başka yollarla denediğimde hiçbiri işe yaramadı eğer çalışıyorsan bana nasıl yapılandırdığını gönderebilirsin
fatih tekin

Cevabımı güncelledim - şimdi aynı zamanda çalışan bir örnek de içeriyor. Yukarıdaki yorumum kısmen yanlış olsa da: ne yazık ki, ne tüm varlıklar için ne allocationSizede initialValueglobal olarak ayarlayamazsınız (tek bir jeneratör kullanmadıkça, ancak IMHO çok okunabilir değildir).
G. Demecki

1
Açıklama için teşekkürler ama yukarıda yazdıklarınız denedim ve hazırda bekletme 5.0.7 ile çalışmadı. Son sürüm daha sonra bu hedefe ulaşabilmek için kaynak kodunu kazdım ve bulabildiğim uygulama buydu hazırda bekletme kaynak kodunda. Yapılandırma kötü görünebilir ama bu maalesef api'yi hazırda bekletiyor ve hazırda bekletme'nin standart EntityManager Uygulamasını kullanıyorum
fatih tekin

1

Ben de Hibernate 5'te bu sorunla karşılaştım:

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
@SequenceGenerator(name = SEQUENCE, sequenceName = SEQUENCE)
private Long titId;

Aşağıda şöyle bir uyarı var:

Kullanımdan kaldırılmış [org.hibernate.id.SequenceHiLoGenerator] sıra tabanlı kimlik oluşturucunun kullanımı bulundu; bunun yerine org.hibernate.id.enhanced.SequenceStyleGenerator kullanın. Ayrıntılar için Hazırda Bekletme Etki Alanı Modeli Eşleme Kılavuzu'na bakın.

Sonra kodumu SequenceStyleGenerator olarak değiştirdim:

@Id
@GenericGenerator(name="cmrSeq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                @Parameter(name = "sequence_name", value = "SEQUENCE")}
)
@GeneratedValue(generator = "sequence_name")
private Long titId;

Bu benim iki sorunumu çözdü:

  1. Kullanımdan kaldırılan uyarı düzeltildi
  2. Şimdi id, oracle dizisine göre üretilir.

0

Şemadaki sıra için DDL'yi kontrol ederdim. JPA Uygulaması yalnızca dizinin doğru tahsis boyutuyla oluşturulmasından sorumludur. Bu nedenle, tahsis boyutu 50 ise, sıranızın DDL'sinde 50'lik artışa sahip olması gerekir.

Bu durum tipik olarak tahsis büyüklüğü 1 olan bir sekansın yaratılmasıyla meydana gelebilir, daha sonra tahsis büyüklüğü 50'ye (veya varsayılan) konfigüre edilir, ancak DDL sekansı güncellenmez.


Demek istediğimi yanlış anlıyorsun. ALTER SEQUENCE ... INCREMENTY BY 50;hiçbir şeyi çözmez, çünkü sorun hala aynı kalır. Sıra değeri hala gerçek varlık kimliklerini yansıtmamaktadır.
G. Demecki

Sorunu daha iyi anlayabilmemiz için lütfen bir test vakası paylaşın.
Hasan Ceylan

1
Test durumu? Neden? Benim tarafımdan gönderilen soru o kadar karmaşık değildi ve zaten cevaplandı. Görünüşe göre HiLo jeneratörünün nasıl çalıştığını bilmiyorsunuz. Her neyse: zamanınızı ve çabanızı feda ettiğiniz için teşekkür ederim.
G. Demecki

1
Gregory, Aslında neden bahsettiğimi biliyorum, şu anda kuluçka aşamasında olan ve Hibernate'i hız olarak 15 kat daha hızlı yenen% 100 JPA Uygulaması olan Batoo JPA yazdım. Öte yandan, sorunuzu yanlış anlamış olabilirim ve Hibernate'i dizilerle birlikte kullanmanın herhangi bir sorun yaratacağını düşünmemiş olabilirim, çünkü 2003'ten beri birçok veritabanında birçok projede Hibernate kullandığım için. Önemli olan soruya çözüm bulmuşsunuz, üzgünüm doğru olarak işaretlenmiş cevabı kaçırdım ...
Hasan Ceylan

Üzgünüm, seni kırmak istemedim. Yardımınız için tekrar teşekkürler, soru cevaplandı.
G. Demecki
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.