2013-09-24 74 views
7

問題概述JPA 2 @SequenceGenerator @GeneratedValue生產違反唯一約束

在看似隨意的時候,我們會得到一個異常「PostgreSQL的重複鍵違反唯一約束。」我確實認爲我知道我們的問題是什麼,但我不想在沒有可重複的測試用例的情況下對代碼進行更改。但是由於我們無法在任何環境中複製它,除了隨機生產外,我要求SO提供援助。

在這個項目中,我們有多個postgres數據庫,併爲每個數據庫中的每個表配置一個主鍵序列。這些序列創建這樣的:

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

我們使用這些序列來生成實體這樣的主鍵:

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

分析

我覺得我認識2個問題此配置:

1)兩個@SequenceGenerators指定相同的名稱屬性,即使它們是應該映射到不同的數據庫序列。

2)@SequenceGenerator的allocationSize屬性默認爲50(我們使用hibernate作爲JPA提供者),所以我認爲創建序列語法應該指定序列應該增加多少,特別是50來匹配allocationSize。

在此基礎上的猜測,我認爲代碼應該進行修改,以這樣的事:

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

我只想測試這個,而不是要求對這樣的問題,但同樣,我們一直沒能在任何其他環境中重現此生產問題。即使在生產中,唯一的約束違規也只發生在看似隨機的時間。

問題:

1)我是在我的改變應該是解決這一問題的唯一約束違規問題分析是正確的?

2)使用hibernate作爲JPA提供程序時使用序列生成器的最佳做法是什麼?

回答

3
  1. 是的,你的分析是正確的。您正確識別了問題(我們遇到了類似的問題)。 而且......如果你要去把在生產中,不要忘了:

    • 無論是手動生成的序列表與正確的初始值/初始ID的新序列發生器(否則hibernate會從開始1,你會再次得到)
    • 或在代碼中設置該值(檢查initalValue@SequenceGenerator)。
  2. 我不能列舉最佳實踐,但我想你可以降低50的限制。我也沒有PostgreSQL的經驗,但在MySQL中你有一個簡單的seq表。發生器和休眠使得整個東西。

0

我也有類似的問題。在我的情況下,我直接通過SQL導入數據。這導致了'hibernate_sequence'的問題。 hibernate_sequence是由id 123,但是我的表中有id大於123的行。