Wir alle kennen das Standardverhalten von Hibernate bei der Verwendung @SequenceGenerator
- es erhöht die reale Datenbanksequenz um eins , multipliziert diesen Wert um 50 (Standardwert allocationSize
) - und verwendet diesen Wert dann als Entitäts-ID.
Dies ist ein falsches Verhalten und widerspricht der Spezifikation, die besagt:
Zuordnungsgröße - (Optional) Der Betrag, um den beim Zuweisen von Sequenznummern aus der Sequenz erhöht werden soll.
Um es klar auszudrücken: Ich kümmere mich nicht um Lücken zwischen generierten IDs.
Ich interessiere mich für IDs, die nicht mit der zugrunde liegenden Datenbanksequenz übereinstimmen . Beispiel: Jede andere Anwendung (die z. B. einfaches JDBC verwendet) möchte möglicherweise neue Zeilen unter IDs einfügen, die aus der Sequenz erhalten wurden. Alle diese Werte werden jedoch möglicherweise bereits von Hibernate verwendet. Wahnsinn.
Kennt jemand eine Lösung für dieses Problem (ohne die allocationSize=1
Leistung einzustellen und damit zu beeinträchtigen)?
EDIT:
Um die Dinge klar zu machen. Wenn der zuletzt eingefügte Datensatz die ID = hatte 1
, verwendet HB Werte 51, 52, 53...
für seine neuen Entitäten, ABER gleichzeitig: Der Wert der Sequenz in der Datenbank wird auf gesetzt 2
. Dies kann leicht zu Fehlern führen, wenn andere Anwendungen diese Sequenz verwenden.
Auf der anderen Seite: Die Spezifikation besagt (nach meinem Verständnis), dass die Datenbanksequenz auf eingestellt sein sollte 51
und in der Zwischenzeit sollte HB Werte aus dem Bereich verwenden 2, 3 ... 50
UPDATE:
Wie Steve Ebersole unten erwähnte: Das von mir beschriebene (und für viele auch intuitivste) Verhalten kann durch Einstellen aktiviert werden hibernate.id.new_generator_mappings=true
.
Danke an alle.
UPDATE 2:
Für zukünftige Leser finden Sie unten ein funktionierendes Beispiel.
@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
die Datenbank nach dem nächsten Wert der Sequenz abfragen muss.SequenceGenerator
Hibernate wird die Datenbank nur abgefragt, wenn die Anzahl der durch angegebenen IDs erschöpftallocationsize
ist. Wenn Sie einrichten,allocationSize = 1
ist dies der Grund, warum der Ruhezustand die Datenbank für jede Einfügung abfragt. Ändern Sie diesen Wert, und Sie sind fertig.hibernate.id.new_generator_mappings
Einstellung ist wirklich wichtig. Ich würde hoffen, dass es die Standardeinstellung ist, dass ich nicht so viel Zeit damit verbringen muss zu recherchieren, warum die ID-Nummer wild wird.Antworten:
Um ganz klar zu sein ... was Sie beschreiben , widerspricht in keiner Weise der Spezifikation. Die Spezifikation bezieht sich auf die Werte, die Hibernate Ihren Entitäten zuweist, nicht auf die Werte, die tatsächlich in der Datenbanksequenz gespeichert sind.
Es besteht jedoch die Möglichkeit, das gewünschte Verhalten zu erhalten. Siehe zuerst meine Antwort auf Gibt es eine Möglichkeit, eine @ GeneratedValue-Strategie mithilfe von JPA-Anmerkungen und Ruhezustand dynamisch auszuwählen? Das gibt Ihnen die Grundlagen. Solange Sie für die Verwendung dieses SequenceStyleGenerator eingerichtet sind, interpretiert Hibernate
allocationSize
den "Pooled Optimizer" im SequenceStyleGenerator. Der "gepoolte Optimierer" ist für die Verwendung mit Datenbanken vorgesehen, die eine "Inkrement" -Option beim Erstellen von Sequenzen ermöglichen (nicht alle Datenbanken, die Sequenzen unterstützen, unterstützen ein Inkrement). Informieren Sie sich dort über die verschiedenen Optimierungsstrategien.quelle
org.hibernate.id.enhanced.SequenceStyleGenerator
. Du hast mich überrascht.allocationSize=1
Es handelt sich um eine Mikrooptimierung vor dem Abrufen der Abfrage. Hibernate versucht, einen Wert im Bereich von assignSize zuzuweisen, und versucht daher, das Abfragen der Datenbank nach Sequenzen zu vermeiden. Diese Abfrage wird jedoch jedes Mal ausgeführt, wenn Sie sie auf 1 setzen. Dies macht kaum einen Unterschied, da beim Zugriff auf Ihre Datenbank durch eine andere Anwendung Probleme auftreten, wenn dieselbe ID zwischenzeitlich von einer anderen Anwendung verwendet wird.Die nächste Generation der Sequenz-ID basiert auf Zuordnungsgröße.
Auf jeden Fall wird es als
50
zu viel gehalten. Es ist auch nur hilfreich, wenn Sie50
in einer Sitzung nahezu Datensätze haben, die nicht beibehalten werden und die mithilfe dieser bestimmten Sitzung und Übertragung beibehalten werden.Daher sollten Sie immer
allocationSize=1
während der Verwendung verwendenSequenceGenerator
. Wie bei den meisten zugrunde liegenden Datenbanken wird die Reihenfolge immer um erhöht1
.quelle
allocationSize=1
Hibernate bei jedersave
Operation die Reise zur Datenbank durchgeführt werden muss, um einen neuen ID-Wert zu erhalten.allocationSize
und versucht daher, das Abfragen der Datenbank nach Sequenzen zu vermeiden. Diese Abfrage wird jedoch jedes Mal ausgeführt, wenn Sie sie auf 1 setzen. Dies macht kaum einen Unterschied, da beim Zugriff auf Ihre Datenbank durch eine andere Anwendung Probleme auftreten, wenn dieselbe ID zwischenzeitlich von einer anderen Anwendung verwendet wirdSteve Ebersole & andere Mitglieder,
würden Sie bitte den Grund für eine ID mit einer größeren Lücke erklären (standardmäßig 50)? Ich verwende Hibernate 4.2.15 und habe den folgenden Code in org.hibernate.id.enhanced.OptimizerFactory cass gefunden.
Immer wenn es auf die Innenseite der if-Anweisung trifft, wird der hi-Wert viel größer. Daher generiert meine ID während des Tests mit dem häufigen Neustart des Servers die folgenden Sequenz-IDs:
1, 2, 3, 4, 19, 250, 251, 252, 400, 550, 750, 751, 752, 850, 1100, 1150.
Ich weiß, dass Sie bereits gesagt haben, dass dies nicht mit der Spezifikation in Konflikt steht, aber ich glaube, dass dies für die meisten Entwickler eine sehr unerwartete Situation sein wird.
Jeder Beitrag wird sehr hilfreich sein.
Jihwan
UPDATE: ne1410s: Danke für die Bearbeitung.
cfrick: OK. Ich werde das machen. Es war mein erster Beitrag hier und ich war mir nicht sicher, wie ich ihn verwenden sollte.
Jetzt habe ich besser verstanden, warum maxLo für zwei Zwecke verwendet wurde: Da der Ruhezustand die DB-Sequenz einmal aufruft, die ID auf Java-Ebene weiter erhöht und in der DB speichert, sollte der ID-Wert auf Java-Ebene berücksichtigen, wie viel ohne Aufruf geändert wurde die DB-Sequenz beim nächsten Aufruf der Sequenz.
Beispielsweise war die Sequenz-ID zu einem Zeitpunkt 1 und der Ruhezustand wurde mit 5, 6, 7, 8, 9 eingegeben (mit Zuordnungsgröße = 5). Wenn wir das nächste Mal die nächste Sequenznummer erhalten, gibt DB 2 zurück, aber im Ruhezustand müssen 10, 11, 12 verwendet werden. Deshalb ist "hi = lastSourceValue.copy (). MultipllyBy (maxLo + 1)" wird verwendet, um eine nächste ID 10 von den 2 zu erhalten, die von der DB-Sequenz zurückgegeben wurden. Es scheint nur störend zu sein, dass während des häufigen Neustarts des Servers und dies war mein Problem mit der größeren Lücke.
Wenn wir also die SEQUENCE-ID verwenden, stimmt die in die Tabelle eingefügte ID nicht mit der SEQUENCE-Nummer in DB überein.
quelle
Nach dem Durchsuchen des Quellcodes im Ruhezustand und der folgenden Konfiguration wird nach 50 Einfügungen der nächste Wert an Oracle db gesendet. Stellen Sie also bei jedem Aufruf ein INST_PK_SEQ-Inkrement von 50 ein.
Der Ruhezustand 5 wird für die folgende Strategie verwendet
Überprüfen Sie auch unten http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence
quelle
allocationSize
nochinitialValue
global für alle Entitäten festlegen (es sei denn, Sie verwenden nur einen Generator, aber meiner Meinung nach ist es nicht sehr lesbar).Auch ich habe dieses Problem in Hibernate 5 gesehen:
Ich habe unten eine Warnung wie diese erhalten:
Dann habe ich meinen Code in SequenceStyleGenerator geändert:
Dies löste meine beiden Probleme:
quelle
Ich würde die DDL für die Sequenz im Schema überprüfen. Die JPA-Implementierung ist nur für die Erstellung der Sequenz mit der richtigen Zuordnungsgröße verantwortlich. Wenn die Zuordnungsgröße 50 ist, muss Ihre Sequenz daher das Inkrement 50 in ihrer DDL haben.
Dieser Fall kann normalerweise beim Erstellen einer Sequenz mit der Zuordnungsgröße 1 auftreten, die später auf die Zuordnungsgröße 50 (oder die Standardgröße) konfiguriert wird, aber die Sequenz-DDL wird nicht aktualisiert.
quelle
ALTER SEQUENCE ... INCREMENTY BY 50;
wird nichts lösen, weil das Problem immer noch das gleiche bleibt. Der Sequenzwert spiegelt immer noch nicht die IDs der realen Entitäten wider.