j'ai l'application gwt connectée à la base de données postgres sur le backend, et une classe Java 'Judgment' mappant la table 'jugements' dans la base de données.
Caused by: org.hibernate.exception.SQLGrammarException: could not get next sequence value
...
Caused by: org.postgresql.util.PSQLException: ERROR: relation "hibernate_sequence" does not exist
ma classe de jugement ressemble à ceci
@Entity
@Table(name = "JUDGEMENTS")
public class Judgement implements Serializable, Cloneable {
private static final long serialVersionUID = -7049957706738879274L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "JUD_ID")
private Long _judId;
...
et mes jugements à la table sont:
Column | Type | Modifiers
-------------+-----------------------------+---------------------------------------------------------
jud_id | bigint | not null default nextval('judgements_id_seq'::regclass)
rating | character varying(255) |
last_update | timestamp without time zone |
user_id | character varying(255) |
id | integer |
Indexes:
"judgements_pkey" PRIMARY KEY, btree (jud_id)
Foreign-key constraints:
"judgements_id_fkey" FOREIGN KEY (id) REFERENCES recommendations(id)
"judgements_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(user_id)
et j'ai un nom de séquence 'judgements_id_seq' dans DB
quelqu'un peut-il me dire ce qui ne va pas ??? Merci.
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.
(UPDATE: il semble que les versions les plus récentes d'Hibernate peuvent utiliser les séquences par table par défaut lorsque GenerationType.IDENTITY
est spécifié. Testez votre version et utilisez-la à la place de l'option ci-dessous si elle vous convient.)
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'elle obtient une valeur d'une séquence, elle peut utiliser cette valeur et les 49 valeurs situées en dessous comme clés uniques. Si vos séquences de base de données incrémentent de 1 (valeur par défaut), cela entraînera des violations uniques, car Hibernate essaiera de réutiliser des clés existantes.
Notez que l’obtention d’une clé à la fois sera entraîne un aller-retour supplémentaire par insertion. Autant que je sache, Hibernate n'est pas capable d'utiliser INSERT ... RETURNING
pour renvoyer efficacement les clés générées, pas plus qu'il ne semble utiliser l'interface de 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
explicitement, ce qui entraînera deux allers-retours. Pour en réduire le coût, vous pouvez définir un incrément plus important sur les séquences de clés comportant de nombreuses insertions, sans oublier de le définir sur le mappage et de la séquence de base de données sous-jacente. Ainsi Hibernate appellera nextval
moins souvent et mettra en cache des blocs de clés à distribuer au fur et à mesure.
Comme vous pouvez le constater ci-dessus, je ne suis pas du tout d'accord avec les choix de conception d'Hibernate effectués ici, du moins en ce qui concerne son utilisation avec PostgreSQL. Ils doivent utiliser getGeneratedKeys
ou INSERT ... RETURNING
avec DEFAULT
pour la clé, ce qui permet à la base de données de s'en occuper sans que Hibernate ait à se préoccuper des noms des séquences ou de leur accès explicite.
En passant, si vous utilisez Hibernate avec Pg, vous voudrez peut-être aussi un déclencheur d'oplock pour Pg afin de permettre au verrouillage optimiste d'Hibernate d'interagir en toute sécurité avec le verrouillage normal de la base de données. Sans cela, vos mises à jour d'Hibernate auront tendance à bloquer les modifications apportées via d'autres clients SQL classiques. Demande-moi comment je sais.
Je semble me souvenir d’avoir utilisé @GeneratedValue(strategy = GenerationType.IDENTITY)
pour que Hibernate utilise des colonnes "série" sur PostgreSQL.
Vous devez définir votre colonne @GeneratedId avec la stratégie GenerationType.IDENTITY au lieu de GenerationType.AUTO.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JUD_ID")
private Long _judId;
J'ai eu la même erreur avant, Tapez cette requête dans votre base de données CREATE SEQUENCE hibernate_sequence START WITH 1 INCREMENT BY 1 NOCYCLE;
ça marche pour moi, bonne chance ~
J'aimerais également ajouter quelques notes sur une migration de MySQL à PostgreSQL:
Pour autant que je m'en souvienne maintenant, espérons que ces astuces vous permettront de gagner quelques minutes d'essais et d'erreurs!
Je pense que vous avez déjà assez de réponses, mais j'ai exactement la même erreur et mon problème était un autre. Et j'ai perdu un peu de temps à essayer de le résoudre.
Dans mon cas, le problème était le propriétaire de la séquence dans Postgres. Par conséquent, si l'une des solutions ci-dessus n'a pas résolu votre problème, vérifiez si le propriétaire de la séquence est l'utilisateur/le rôle qui doit disposer de l'autorisation.
Suit un échantillon:
CREATE SEQUENCE seq_abcd
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public.seq_abcd OWNER TO USER_APP;
J'espère que cela peut être utile à n'importe qui.
Utilisation de GeneratedValue
et GenericGenerator
avec la stratégie native
:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_native")
@GenericGenerator(name = "id_native", strategy = "native")
@Column(name = "id", updatable = false, nullable = false)
private Long id;
Je devais créer un appel de séquence hibernate_sequence
car Hibernate recherchait une telle séquence par défaut:
create sequence hibernate_sequence start with 1 increment by 50;
grant usage, select on all sequences in schema public to my_user_name;
La base de données que nous utilisons doit être mentionnée sous search_path dans le fichier de configuration SQL de Postgres. Cela peut être fait en modifiant le fichier de configuration Postgressql en définissant search_path avec le nom de la base de données, par exemple: TESTDB.
Cela a fonctionné pour moi après avoir apporté le changement ci-dessus.