hibernate n'a pas pu obtenir la prochaine valeur de séquence

J'ai gwt application connect to Postgres DB au backend, et une classe java 'Judgement' mappant la table 'judgements' dans DB, quand j'ai essayé de persister un jugement dans db, il a jeté les erreurs suivantes:

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

Mon Cours 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 de 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??? grâce.

42
demandé sur user468587 2012-05-17 03:28:49

8 réponses

Le dialecte PostgreSQL D'Hibernate n'est pas très brillant. Il ne connaît pas vos séquences par série, 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 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 ceci au lieu de ce qui suit si cela fonctionne pour vous.)


Vous devez changer vos mappages pour explicitement spécifiez 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 {[3] } donc quand elle obtient une valeur d'une séquence, elle peut utiliser cette valeur et les 49 valeurs en dessous {[23] } Comme 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 tente de réutiliser les clés existantes.

Notez que obtenir une clé à la fois entraînera un aller-retour supplémentaire par insert. Pour 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 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 explicitement, ce qui entraînera 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 souvenant de le définir sur le mappage et de la séquence de base de données sous-jacente. Cela entraînera Hibernate à appeler nextval moins fréquemment et à mettre en cache des blocs de clés à distribuer au fur et à mesure.

Je suis sûr que vous pouvez voir de ce qui précède que je ne suis pas d'accord avec les choix de conception Hibernate faits ici, au moins du point de vue de L'utiliser avec PostgreSQL. Ils devraient utiliser getGeneratedKeys ou utiliser INSERT ... RETURNING avec DEFAULT pour la clé, laissant la base de données s'en occuper sans que Hibernate ait à se soucier de lui-même les noms des séquences ou explicite accès.

BTW, si vous utilisez Hibernate avec Pg, vous voudrez peut-être aussi un déclencheur oplock pour Pg pour permettre au verrouillage optimiste D'Hibernate d'interagir en toute sécurité avec le verrouillage de base de données normal. Sans cela ou quelque chose comme ça, vos mises à jour Hibernate auront tendance à bloquer les modifications apportées via d'autres clients SQL réguliers. Me demandez comment je le sais.

79
répondu Craig Ringer 2014-11-23 15:21:01

Je me souviens avoir dû utiliser @GeneratedValue(strategy = GenerationType.IDENTITY) pour obtenir Hibernate pour utiliser des colonnes 'serial' sur PostgreSQL.

40
répondu davidg 2015-01-06 14:01:02

Vous devez définir votre colonne @ GeneratedId avec strategy GenerationType.Identité au lieu de GenerationType.AUTO

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JUD_ID")
private Long _judId;
11
répondu virag 2015-10-01 00:54:19

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;

C'est du travail pour moi, Bonne Chance ~

7
répondu splatter_fadli 2013-10-11 09:09:55

Je voudrais aussi ajouter quelques notes sur une migration MySQL-to-PostgreSQL:

  1. dans votre DDL, dans la dénomination de l'objet, préférez l'utilisation du caractère '_' (trait de soulignement) pour la séparation des mots à la convention camel case. Ce dernier fonctionne bien dans MySQL mais apporte beaucoup de problèmes dans PostgreSQL.
  2. la stratégie D'identité pour l'annotation @GeneratedValue dans vos champs d'identité de classe de modèle fonctionne correctement pour PostgreSQLDialect dans hibernate 3.2 et supérieur. En outre, la stratégie automobile est le paramètre typique pour MySQLDialect.
  3. Si vous annotez vos classes de modèle avec @Table et définissez une valeur littérale égale au nom de la table, assurez-vous d'avoir créé les tables à stocker sous schéma public.

C'est aussi loin que je me souviens maintenant, j'espère que ces conseils peuvent vous épargner quelques minutes d'essais et d'erreurs!

2
répondu RickB 2013-03-08 04:18:39

Je pense que vous avez déjà assez de réponse, mais j'ai eu 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. Donc, si une solution ci-dessus n'a pas résolu votre problème, vérifiez si le propriétaire de la séquence est l'utilisateur/rôle qui devrait avoir 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 pour n'importe qui.

2
répondu Ventura 2013-06-19 16:01:35

La base de données que nous utilisons doit être mentionnée sous search_path dans le fichier de Configuration SQL Postgres. Cela peut être fait en éditant le fichier de configuration Postgressql en définissant search_path avec le nom de la base de données par exemple: TESTDB.

  1. Trouver postgressql.fichier conf sous le dossier de données de Postgres SQL datbase.
  2. Set search_path = "$utilisateur", public, TESTDB;
  3. Redémarrez le service SQL Postgres pour modifier la modification.

Cela a fonctionné pour moi après avoir fait le changement ci-dessus.

0
répondu Chaitanya Ankam 2018-01-02 12:17:32

En utilisant les 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;

J'ai dû créer un appel de séquence hibernate_sequence car Hibernate recherche 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;
0
répondu Stephane 2018-06-28 21:41:42