Le dialecte PostgreSQL d'Hibernate n'est pas très brillant. Il ne connaît pas vos séquences par SERIAL et suppose qu'il existe une séquence globale à l'échelle de la base de données appelée "hibernate_sequence" qu'il peut utiliser.
(MISE À JOUR :Il semble que les nouvelles versions d'Hibernate peuvent utiliser les séquences par défaut par table lorsque GenerationType.IDENTITY
est spécifié. Testez votre version et utilisez-la à la place de celle ci-dessous si elle fonctionne pour vous.)
Vous devez modifier vos mappages pour spécifier explicitement chaque séquence. C'est ennuyeux, répétitif et 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;
...
Le allocationSize=1
est assez important. Si vous l'omettez, Hibernate supposera aveuglément que la séquence est définie avec INCREMENT 50
ainsi, lorsqu'il obtient une valeur d'une séquence, il peut utiliser cette valeur et les 49 valeurs en dessous en tant que clés générées uniques. Si vos séquences de base de données incrémentent de 1 - la valeur par défaut - cela entraînera des violations uniques car Hibernate essaiera de réutiliser les clés existantes.
Notez que l'obtention d'une clé à la fois permet entraîner un aller-retour supplémentaire par insert. Autant que je sache, Hibernate n'est pas capable d'utiliser INSERT ... RETURNING
pour renvoyer efficacement les clés générées, et il ne peut apparemment pas non plus utiliser l'interface des clés générées par JDBC. Si vous lui dites d'utiliser une séquence, il appellera nextval
pour obtenir la valeur puis insert
cela explicitement, résultant en deux allers-retours. Pour réduire le coût de cela, vous pouvez définir un incrément plus important sur les séquences de touches avec beaucoup d'inserts, en vous rappelant de le définir sur le mappage et la séquence de base de données sous-jacente. Cela amènera Hibernate à appeler nextval
moins fréquemment et cache des blocs de clés à distribuer au fur et à mesure.
Je suis sûr que vous pouvez voir d'après ce qui précède que je ne suis pas d'accord avec les choix de conception Hibernate faits ici, du moins du point de vue de son utilisation avec PostgreSQL. Ils devraient utiliser getGeneratedKeys
ou en utilisant INSERT ... RETURNING
avec DEFAULT
pour la clé, laissant la base de données s'en occuper sans qu'Hibernate ait à se soucier des noms des séquences ou d'un accès explicite à celles-ci.
BTW, si vous utilisez Hibernate avec Pg, vous souhaiterez peut-être également un déclencheur oplock pour Pg pour permettre au verrouillage optimiste d'Hibernate d'interagir en toute sécurité avec le verrouillage normal de la base de données. Sans cela ou quelque chose comme ça, vos mises à jour Hibernate auront tendance à encombrer les modifications apportées via d'autres clients SQL réguliers. Demandez-moi comment je sais.