Hibernate annotation für PostgreSQL serial geben
Ich habe eine PostgreSQL-Tabelle, in der ich eine Spalte inv_seq
erklärt serial
.
Ich habe eine Hibernate-bean-Klasse zum anzeigen der Tabelle. Alle anderen Spalten sind richtig Lesen, außer dieser Spalte. Hier ist die Erklärung in der Hibernate-bean-Klasse:
....
....
@GeneratedValue(strategy=javax.persistence.GenerationType.AUTO)
@Column(name = "inv_seq")
public Integer getInvoiceSeq() {
return invoiceSeq;
}
public void setInvoiceSeq(Integer invoiceSeq) {
this.invoiceSeq = invoiceSeq;
}
....
....
Ist die Erklärung korrekt?
Ich bin in der Lage, um zu sehen, die fortlaufenden Nummern generiert, indem die Spalte in der Datenbank, aber ich bin nicht in der Lage, auf Sie zuzugreifen, die in der java-Klasse.
Bitte helfen.
- Aufgegeben Frage?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gefahr: Ihre Frage impliziert, dass Sie machen können ein design Fehler - Sie versuchen, eine Datenbank-Sequenz für ein "business" - Wert, der dem Benutzer präsentiert werden, in diesem Fall Rechnung zahlen.
Nicht eine Sequenz verwenden, wenn Sie brauchen, um etwas mehr als ein test der Wert für die Gleichstellung. Es hat keine Ordnung. Es hat keinen "Abstand" von einem anderen Wert. Es ist nur gleich, oder nicht gleich.
Rollback:
Sequenzen sind in der Regel nicht geeignet ist für solche verwendet werden, da änderungen an Sequenzen sind nicht Rollback mit der Transaktion
ROLLBACK
. Finden Sie die Fußzeilen auf Funktionen-Sequenz undCREATE SEQUENCE
.Rollbacks sind zu erwarten und normal. Sie treten aufgrund von:
SERIALIZABLE
oder snapshot-isolation-Transaktionen... und mehr.
Ihre Anwendung haben "Löcher" in der Rechnung Nummerierung, wo diese rollbacks auftreten. Zusätzlich, dort ist keine Bestellung garantieren, so ist es durchaus möglich, dass eine Transaktion mit einem späteren Sequenz-Nummer zu Begehen, früher (manchmal viel früher), als man mit einer späteren Nummer.
Chunking:
Es ist auch normal für einige Anwendungen, einschließlich Ruhezustand, schnappen Sie mehr als einen Wert von einer Sequenz zu einer Zeit, und Sie aus der hand zu Transaktionen intern. Das ist zulässig, weil Sie nicht erwarten sollen, Sequenz-generierte Werte zu haben, eine sinnvolle Reihenfolge, oder werden die in irgendeiner Weise vergleichbar außer für die Gleichstellung. Für Rechnung Nummerierung, die Sie wollen bestellen zu, so dass Sie nicht an alle freuen, wenn Hibernate packt Werte 5900-5999 und beginnt mit übergabe Sie aus 5999 zählen unten oder abwechselnd-dann nach unten, so dass Sie Ihre Rechnung zahlen gehen: n, n+1, n+49, n+2, n+48, ... n+50, n+99, n+51, n+98, [n+52 verloren rollback], n+97, .... Ja, die high-dann low-Zuweisung existiert in Hibernate.
Es hilft nicht, dass, es sei denn, Sie definieren einzelne
@SequenceGenerator
s in Ihren Zuordnungen, Hibernate teilen mag eine einzelne Sequenz für jeder generierte ID, zu. Hässlich.Korrekte Verwendung:
Einer Sequenz ist nur angemessen, wenn Sie nur erfordern die Nummerierung eindeutig sein. Wenn Sie auch brauchen, es zu sein, die monotone und Ordnungszahl, sollten Sie sich Gedanken über die Verwendung eines gewöhnlichen Tisch mit einem Zähler-Feld über
UPDATE ... RETURNING
oderSELECT ... FOR UPDATE
("pessimistisches locking" in den Ruhezustand) oder via Hibernate optimistische sperren. Auf diese Weise können Sie garantieren lückenlose Schritten, ohne Löcher oder out-of-order-Einträge., Was zu tun ist, anstatt:
Erstellen Sie eine Tabelle nur für einen Zähler. Eine einzelne Zeile in es, und aktualisieren Sie es wie Sie es Lesen. Werde es sperren, verhindern, dass andere Transaktionen bekommen eine ID, bis deins verpflichtet.
Weil es zwingt alle Ihre Transaktionen zu betreiben, Seriell, versuchen Sie, um Transaktionen zu generieren, Rechnung IDs kurz und vermeiden Sie dabei mehr arbeiten, als Sie müssen.
Alternativ können Sie:
@Version
Spalte, und lassen Sie das optimistische sperren kümmern, Konflikte;Alle diese Optionen werden Ihre Transaktionen zu serialisieren - entweder durch ein Rollback Konflikte mit der @Version, oder eine Blockierung (Verriegelung), bis der lock-Halter verpflichtet. so oder so, gapless-Sequenzen wirklich langsam, dass Bereich der Sie Ihre Anwendung, so verwenden Sie nur lückenlose Sequenzen, wenn Sie zu haben.
@GenerationType.TABLE
: Es ist verlockend, zu verwenden@GenerationType.TABLE
mit einem@TableGenerator(initialValue=1, ...)
. Leider, während GenerationType.TABELLE können Sie angeben, eine Zuordnung Größe via @TableGenerator, es nicht bieten keine Garantien bezüglich der Bestellung oder der rollback-Verhalten. Finden Sie die JPA-2.0-Spezifikation, Abschnitt 11.1.46, und 11.1.17. Insbesondere "Diese Spezifikation definiert jedoch nicht das genaue Verhalten dieser Strategien. und Fußnote 102 "Portable Anwendungen, sollten Sie nicht verwenden die GeneratedValue-annotation auf andere persistente Felder oder Eigenschaften [als@Id
Primärschlüssel]". So ist es unsicher ist, verwenden Sie@GenerationType.TABLE
für die Nummerierung, die Sie benötigen, um gapless oder Nummerierung, die nicht auf eine Primärschlüssel-Eigenschaft, es sei denn, dein JPA-provider macht mehr Garantien als der standard.Wenn Sie fest sind, mit einer Folge:
Dem Plakat fest, dass Sie vorhandene apps mit der DB, die eine Sequenz verwenden, die bereits, so dass Sie ' re mit es stecken.
In der JPA-standard garantiert nicht, dass Sie verwenden können, erzeugt Spalten bis auf @Id, können Sie (a) ignorieren Sie das und gehen Sie vor, so lange, wie Sie Ihre Anbieter können, oder (b) machen Sie den Einsatz mit einem Standard-Wert und neu aus der Datenbank gelesen. Letzteres ist sicherer:
Weil
insertable=false
die Anbieter nicht versuchen, geben Sie einen Wert für die Spalte. Sie können nun legen Sie einen geeignetenDEFAULT
in der Datenbank, wienextval('some_sequence')
und es werden geehrt. Haben Sie vielleicht eine re-Lesen Sie die Entität aus der Datenbank mitEntityManager.refresh()
nach anhaltenden es - ich bin nicht sicher, ob das Persistenz-provider machen das für Sie, und ich habe nicht geprüft, spec oder geschrieben, ein demo-Programm.Der einzige Nachteil ist, dass es scheint, die Spalte kann nicht gemacht werden, @ NotNull oder
nullable=false
, weil die Anbieter nicht begreifen, dass die Datenbank einen Standardwert für die Spalte. Kann es immer nochNOT NULL
in der Datenbank.Wenn Sie Glück haben anderen apps, wird auch die standard-Ansatz, der entweder das weglassen der Spalte "Sequenz" aus der
INSERT
's column list oder explizite Angabe der keyword -DEFAULT
als der Wert, anstelle von aufrufennextval
. Es wird nicht schwer sein zu finden, dass durch die Aktivierunglog_statement = 'all'
impostgresql.conf
und Suche in den logs. Wenn Sie das tun, dann können Sie tatsächlich schalten Sie alles, um lückenlose wenn Sie sich entscheiden, Sie brauchen, um durch den Austausch IhrerDEFAULT
mit einemBEFORE INSERT ... FOR EACH ROW
- trigger-Funktion, die SätzeNEW.invoice_number
von der Zähler-Tabelle.@@SequenceGenerator
und befassen sich mit der out-of-order-Einträge und die Lücken. Wenn die anderen apps wurden mit dieser Methode in der Vergangenheit dann Ihre Anforderungen klar damit - implizit oder explizit - Lücken in der generierten ID.nextval
auf die Sequenz direkt dann weisen Sie das Ergebnis. Oder Sie können festlegen, dass die Spalte als@ Basic(insertable=false)
und aktualisieren Sie die Einheit sofort nach dem anhalten, so dass die DatenbankDEFAULT
Wert zugeordnet ist und abgeholt werden.Habe ich festgestellt, dass hibernate 3.6 versucht, mithilfe einer einzigen Sequenz für alle Personen, wenn Sie legen Sie es auf AUTO also in meiner Anwendung verwende ich IDENTITÄT als die generation Strategie.
@Craig hatte einige sehr gute Punkte über Rechnung zahlen zu müssen Inkrementieren, wenn Sie präsentieren Sie auf Benutzer, und er schlug mit Hilfe einer Tabelle für, die. Wenn Sie am Ende mit einer Tabelle zum speichern der nächsten id, die Sie vielleicht in der Lage zu verwenden ein mapping, ähnlich wie diese.
GenerationType.TABLE
können Sie angeben, eine Zuordnung Größe über@TableGenerator
es nicht bieten keine Garantien bezüglich der Bestellung oder der rollback-Verhalten. Finden Sie die JPA-2.0-Spezifikation, Abschnitt 11.1.46, und 11.1.17. Insbesondere "Diese Spezifikation definiert jedoch nicht das genaue Verhalten dieser Strategien." und Fußnote 102 "Portable Anwendungen, sollten Sie nicht verwenden die GeneratedValue-annotation auf andere persistente Felder oder Eigenschaften [als @Id Primärschlüssel]". Es ist nicht sicher zu verwenden, für die Nummerierung, die Sie benötigen, um gapless-es sei denn, dein JPA-provider macht mehr Garantien als der standard.Je nach situation, kann dies nicht funktionieren. Es gibt einen bug eröffnet gegen Hibernate, Dokumente, die für dieses Verhalten.
http://opensource.atlassian.com/projects/hibernate/browse/HHH-4159
Wenn Sie offen sind mit einer mapping-Datei, anstelle von Anmerkungen, ich habe wieder das Problem (NULL in der SERIELLEN Spalten, die nicht Teil des Primärschlüssels). Mit der "generated" - Attribut des property-Elements bewirkt, dass Hibernate re-read der Reihe nach einer insert -, pick-up die generierte Spalte Wert:
integer
mit einemdefault nextval('tblname_colname_seq')
imCREATE TABLE
, nicht ein echter Typ. Verwendeninteger
.Verwende ich Postgres + Hibernate in meinen Projekten und das ist, was ich Tue:
Es funktioniert gut für mich.