PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Hibernate konnte den nächsten Sequenzwert nicht abrufen

Der PostgreSQL-Dialekt von Hibernate ist nicht sehr hell. Es kennt Ihre per-SERIAL-Sequenzen nicht und geht davon aus, dass es eine globale datenbankweite Sequenz namens "hibernate_sequence" gibt, die es verwenden kann.

(AKTUALISIEREN :Es scheint, dass neuere Hibernate-Versionen die Standardsequenzen pro Tabelle verwenden können, wenn GenerationType.IDENTITY angegeben. Testen Sie Ihre Version und verwenden Sie diese anstelle der folgenden, wenn sie für Sie funktioniert.)

Sie müssen Ihre Zuordnungen ändern, um jede Sequenz explizit anzugeben. Es ist lästig, wiederholt sich und ist sinnlos.

@Entity
@Table(name = "JUDGEMENTS")
public class Judgement implements Serializable, Cloneable {

    private static final long serialVersionUID = -7049957706738879274L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="judgements_id_seq")
    @SequenceGenerator(name="judgements_id_seq", sequenceName="judgements_id_seq", allocationSize=1)
    @Column(name = "JUD_ID")
    private Long _judId;
...

Die allocationSize=1 ist ganz wichtig. Wenn Sie es weglassen, geht Hibernate blind davon aus, dass die Sequenz mit INCREMENT 50 definiert ist Wenn es also einen Wert aus einer Sequenz erhält, kann es diesen Wert und die 49 Werte darunter verwenden als eindeutig generierte Schlüssel. Wenn Ihre Datenbanksequenzen um 1 erhöht werden - die Standardeinstellung -, führt dies zu eindeutigen Verletzungen, da Hibernate versucht, vorhandene Schlüssel wiederzuverwenden.

Beachten Sie, dass es geht, jeweils nur einen Schlüssel zu erhalten führen zu einem zusätzlichen Hin- und Rückweg pro Insert. Soweit ich das beurteilen kann, ist Hibernate nicht in der Lage, INSERT ... RETURNING zu verwenden um generierte Schlüssel effizient zurückzugeben, noch kann es anscheinend die von JDBC generierte Schlüsselschnittstelle verwenden. Wenn Sie ihm sagen, dass er eine Sequenz verwenden soll, ruft er nextval auf um den Wert zu erhalten, dann insert das ausdrücklich, was zu zwei Hin- und Rückfahrten führt. Um die Kosten dafür zu reduzieren, können Sie eine größere Schrittweite für Tastenfolgen mit vielen Einfügungen festlegen, wobei Sie daran denken müssen, sie auf den Zuordnungen und festzulegen die zugrunde liegende Datenbanksequenz. Dadurch ruft Hibernate nextval auf weniger häufig und Schlüsselblöcke zwischenspeichern, um sie nach und nach zu verteilen.

Ich bin mir sicher, dass Sie aus dem Obigen ersehen können, dass ich mit den hier getroffenen Hibernate-Entwurfsentscheidungen nicht einverstanden bin, zumindest aus der Perspektive der Verwendung mit PostgreSQL. Sie sollten getGeneratedKeys verwenden oder mit INSERT ... RETURNING mit DEFAULT für den Schlüssel, dies der Datenbank überlassen, ohne dass sich Hibernate um die Namen der Sequenzen oder den expliziten Zugriff darauf kümmern muss.

Übrigens, wenn Sie Hibernate mit Pg verwenden, möchten Sie möglicherweise auch einen Oplock-Trigger für Pg, damit die optimistische Sperre von Hibernate sicher mit der normalen Datenbanksperrung interagieren kann. Ohne sie oder etwas Ähnliches neigen Ihre Hibernate-Updates dazu, Änderungen zu überschreiben, die über andere reguläre SQL-Clients vorgenommen wurden. Fragen Sie mich, woher ich das weiß.