2013-09-24 27 views
7

Problema PanoramicaJPA 2 @SequenceGenerator @GeneratedValue produzione di violazione di vincolo unico

A volte apparentemente casuali otteniamo un'eccezione "chiave duplicata PostgreSQL viola vincolo univoco." Penso di sapere quale sia il nostro problema "s" ma non voglio apportare modifiche al codice senza avere un caso di test riproducibile. Ma dal momento che non siamo stati in grado di riprodurlo in un ambiente diverso da quello casuale nella produzione, sto chiedendo assistenza da SO.

In questo progetto sono presenti più database Postgres e una sequenza di chiavi primaria configurata per ogni tabella in ciascun database. Queste sequenze sono creati in questo modo:

create sequence PERSONS_SEQ; 
create sequence VISITS_SEQ; 
etc... 

Usiamo queste sequenze per generare le chiavi primarie per le entità come questo:

@Entity 
@Table(name = "visits") 
public class Visit { 
    @Id 
    @Column(name = "id") 
    @SequenceGenerator(name = "seq", sequenceName = "visits_seq") 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq") 
    private int id; 
    ... 
} 

@Entity 
@Table(name = "person") 
public class Person { 
    @Id 
    @Column(name = "id") 
    @SequenceGenerator(name = "seq", sequenceName = "persons_seq") 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq") 
    private int id; 
    ... 
} 

Analisi

Credo di riconoscere 2 problemi con questa configurazione:

1) Entrambi i @SequenceGenerators specificano lo stesso attributo nome anche se sono supposto per mappare a diverse sequenze di database.

2) L'attributo @SequenceGenerator allocationSize è impostato su 50 (stiamo utilizzando l'ibernazione come provider JPA), quindi penso che la sintassi della sequenza di creazione dovrebbe specificare quanto deve aumentare la sequenza, in particolare di 50 per abbinare allocazione.

Sulla base di questa ipotesi, penso che il codice deve essere modificato per qualcosa di simile:

create sequence PERSONS_SEQ increment by 50; 
create sequence VISITS_SEQ increment by 50; 
etc... 

@Entity 
@Table(name = "visits") 
public class Visit { 
    @Id 
    @Column(name = "id") 
    @SequenceGenerator(name = "visits_seq", sequenceName = "visits_seq") 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "visits_seq") 
    private int id; 
    ... 
} 

@Entity 
@Table(name = "person") 
public class Person { 
    @Id 
    @Column(name = "id") 
    @SequenceGenerator(name = "persons_seq", sequenceName = "persons_seq") 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "persons_seq") 
    private int id; 
    ... 
} 

vorrei solo provare questo piuttosto che porre la domanda su SO, ma ancora una volta, non siamo stati in grado di riprodurre questo problema di produzione in qualsiasi altro ambiente. E anche nella produzione, la violazione del vincolo univoco si verifica solo in momenti apparentemente casuali.

Domande:

1) Ho ragione nella mia analisi di ciò che i cambiamenti dovrebbero essere quello di correggere questa violazione vincolo univoco?

2) Quali sono le migliori pratiche per l'utilizzo di generatori di sequenza quando si utilizza l'ibernazione come provider JPA?

risposta

3
  1. Sì, l'analisi è corretta. Hai identificato correttamente il problema (abbiamo avuto un problema simile). E ... se vuoi che mettere in produzione, non dimenticate di:

    • sia generare manualmente la tabella di sequenza per il nuovo generatore di sequenza con il corretto valore iniziale/ID iniziale (altrimenti hibernate inizierà da 1 e si otterrà di nuovo)
    • o impostare tale valore in Codice (controllare initalValue in @SequenceGenerator).
  2. Non sono in grado di enumerare le migliori pratiche, ma suppongo che potresti abbassare il limite di 50.Inoltre non ho esperienza con PostgreSQL, ma in MySQL hai una semplice tabella per il seq. generatore e ibernazione rendono l'intera roba.

0

Ho un problema simile. Nel mio caso, ho importato i dati direttamente tramite SQL. Ciò ha causato un problema con "hibernate_sequence". Hibernate_sequence era di id 123 ma nella mia tabella c'erano delle righe in cui l'ID era maggiore di 123.

Problemi correlati