PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

hibernate non è stato in grado di ottenere il valore della sequenza successiva

Il dialetto PostgreSQL di Hibernate non è molto brillante. Non conosce le tue sequenze per-SERIAL e presume che esista una sequenza globale a livello di database chiamata "hibernate_sequence" che può utilizzare.

(AGGIORNAMENTO :Sembra che le versioni più recenti di Hibernate possano utilizzare le sequenze predefinite per tabella quando GenerationType.IDENTITY è specificato. Testa la tua versione e usa questa invece di quella di seguito se funziona per te.)

È necessario modificare le mappature per specificare in modo esplicito ciascuna sequenza. È fastidioso, ripetitivo e inutile.

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

Il allocationSize=1 è abbastanza importante. Se lo ometti, Hibernate presumerà ciecamente che la sequenza sia definita con INCREMENT 50 quindi quando ottiene un valore da una sequenza può utilizzare quel valore e i 49 valori sottostanti come chiavi generate univoche. Se le sequenze del tuo database aumentano di 1, l'impostazione predefinita, ciò comporterà violazioni univoche poiché Hibernate tenta di riutilizzare le chiavi esistenti.

Tieni presente che ottenere una chiave alla volta sarà comporta un ulteriore viaggio di andata e ritorno per inserto. Per quanto ne so, Hibernate non è in grado di utilizzare INSERT ... RETURNING per restituire in modo efficiente le chiavi generate, né apparentemente può utilizzare l'interfaccia delle chiavi generate da JDBC. Se gli dici di usare una sequenza, chiamerà nextval per ottenere il valore, quindi insert questo in modo esplicito, risultando in due viaggi di andata e ritorno. Per ridurre il costo di ciò, puoi impostare un incremento maggiore sulle sequenze di tasti con molti inserti, ricordandoti di impostarlo sulla mappatura e la sequenza del database sottostante. Ciò farà sì che Hibernate chiami nextval meno frequentemente e memorizza nella cache blocchi di chiavi da distribuire man mano.

Sono sicuro che puoi vedere da quanto sopra che non sono d'accordo con le scelte di progettazione di Hibernate fatte qui, almeno dal punto di vista dell'utilizzo con PostgreSQL. Dovrebbero usare getGeneratedKeys oppure utilizzando INSERT ... RETURNING con DEFAULT per la chiave, lasciando che il database se ne occupi senza che Hibernate si debba preoccupare dei nomi delle sequenze o dell'accesso esplicito ad esse.

A proposito, se stai usando Hibernate con Pg, probabilmente vorrai anche un trigger di oplock per Pg per consentire al blocco ottimistico di Hibernate di interagire in modo sicuro con il normale blocco del database. Senza di esso o qualcosa del genere, gli aggiornamenti di Hibernate tenderanno a rovinare le modifiche apportate tramite altri normali client SQL. Chiedimi come lo so.