52

gwt アプリケーションをバックエンドで postgres DB に接続し、Java クラス 'Judgement' を DB のテーブル 'judgements' にマッピングします。決定を db に永続化しようとすると、次のエラーがスローされました。

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

私の判断クラスは次のようになります

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

私のテーブルジャッジメントは次のとおりです。

   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)

そして、私はDBに「judgements_id_seq」というSEQUENCE名を持っています

誰が何が悪いのか教えてもらえますか?ありがとう。

4

11 に答える 11

93

HibernateのPostgreSQL方言はあまり明るくありません。SERIALごとのシーケンスについては認識せず、使用できる「hibernate_sequence」と呼ばれるデータベース全体のグローバルシーケンスがあると想定しています。


更新:新しいHibernateバージョンは、GenerationType.IDENTITYが指定されている場合、デフォルトのテーブルごとのシーケンスを使用する可能性があるようです。バージョンをテストし、機能する場合は、以下の代わりにこれを使用してください。)


各シーケンスを明示的に指定するには、マッピングを変更する必要があります。それは迷惑で、反復的で、無意味です。

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

これallocationSize=1は非常に重要です。これを省略すると、Hibernateはシーケンスがで定義されていると盲目的に想定するINCREMENT 50ため、シーケンスから値を取得するときに、その値とその下の49個の値を一意の生成キーとして使用できます。データベースシーケンスが1(デフォルト)ずつインクリメントする場合、Hibernateが既存のキーを再利用しようとするため、これにより一意の違反が発生します。

一度に1つのキーを取得すると、挿入ごとに追加のラウンドトリップが発生することに注意してください。私が知る限り、HibernateはINSERT ... RETURNING生成されたキーを効率的に返すために使用することはできず、JDBCで生成されたキーインターフェイスを使用することもできません。シーケンスを使用するように指示するとnextval、値を取得するために呼び出し、次にinsertその値を明示的に取得するため、2回のラウンドトリップが発生します。そのコストを削減するために、多くの挿入を含むキーシーケンスに大きな増分を設定できます。これは、マッピング基になるデータベースシーケンスに設定することを忘れないでください。これにより、Hibernateが呼び出すnextval頻度が減り、キーのブロックがキャッシュされて配布されます。

上記から、少なくともPostgreSQLで使用するという観点からは、ここで行ったHibernateの設計の選択に同意できないことがわかると思います。getGeneratedKeysキーにwithまたはINSERT ... RETURNINGwithを使用する必要がDEFAULTあります。これにより、Hibernateがシーケンスの名前やシーケンスへの明示的なアクセスに問題を起こすことなく、データベースがこれを処理できるようになります。

ところで、PgでHibernateを使用している場合は、Pgのoplockトリガーを使用して、Hibernateの楽観的ロックが通常のデータベースロックと安全に相互作用できるようにすることもできます。それまたはそのようなものがないと、Hibernateの更新は他の通常のSQLクライアントを介して行われた変更を覆い隠す傾向があります。どうやって知っているのか聞いてください。

于 2012-05-17T01:00:47.747 に答える
45

@GeneratedValue(strategy = GenerationType.IDENTITY)HibernateにPostgreSQLで「シリアル」列を使用させるために使用する必要があったことを思い出しているようです。

于 2012-05-17T00:05:13.277 に答える
11

前に同じエラーが発生しました。データベースにこのクエリを入力してくださいCREATE SEQUENCE hibernate_sequence START WITH 1 INCREMENT BY 1 NOCYCLE;

それは私の仕事です、頑張ってください〜

于 2013-10-11T09:09:55.103 に答える
2

また、MySQLからPostgreSQLへの移行に関するいくつかのメモを追加したいと思います。

  1. DDLでは、オブジェクトの命名で、キャメルケースの規則よりも単語の区切りに「_」(アンダースコア)文字を使用することをお勧めします。後者はMySQLで正常に機能しますが、PostgreSQLでは多くの問題を引き起こします。
  2. モデルクラスIDフィールドの@GeneratedValueアノテーションのIDENTITY戦略は、Hibernate3.2以降のPostgreSQLDialectで正常に機能します。また、AUTO戦略は、MySQLDialectの一般的な設定です。
  3. モデルクラスに@Tableアノテーションを付け、リテラル値をテーブル名と同じ値に設定する場合は、パブリックスキーマの下に格納されるテーブルを作成したことを確認してください。

これは私が今覚えている限りですが、これらのヒントが数分間の試行錯誤を省くことができることを願っています!

于 2013-03-08T04:18:39.940 に答える
2

あなたはすでに十分な答えを持っていると思いますが、まったく同じエラーが発生し、私の問題は別のものでした. そして、私はそれを解決しようとして少し時間を無駄にしました.

私の場合、問題は Postgres のシーケンスの所有者でした。したがって、上記の解決策で問題が解決しない場合は、シーケンスの所有者が権限を持つ必要があるユーザー/ロールであるかどうかを確認してください。

サンプルに従います:

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;

誰にとっても役立つことを願っています。

于 2013-06-19T16:01:35.083 に答える
0

次のクエリを使用して、テーブルを変更してください。 CREATE SEQUENCE user_id_seq START 1; ALTER TABLE product.users ALTER COLUMN user_id SET DEFAULT nextval('user_id_seq'); ALTER SEQUENCE users.user_id_seq OWNED BY users.user_id;

エンティティクラスで this を使用します

@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="user_id_seq")

于 2019-09-23T17:52:50.350 に答える