バックエンドでgwtアプリケーションをpostgres DBに接続し、DBのテーブル 'judgements'をマッピングするJava class 'Judgement'、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」を持っています
誰が間違っているのか教えてもらえますか???ありがとう。
HibernateのPostgreSQL方言はそれほど明るくありません。 SERIALごとのシーケンスについては知らず、使用できる「hibernate_sequence」と呼ばれるグローバルなデータベース全体のシーケンスがあると想定しています。
([〜#〜] update [〜#〜]:新しいバージョンの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
を使用するか、キーにDEFAULT
とともにINSERT ... RETURNING
を使用する必要があります。これにより、データベースはHibernateがシーケンスの名前や明示的なアクセスをめぐって問題なく処理できます。
ところで、PgでHibernateを使用している場合は、おそらく Pgのoplockトリガー を使用して、Hibernateの楽観的ロックが通常のデータベースロックと安全に対話できるようにすることもできます。 Hibernateの更新は、他の通常のSQLクライアントを介して行われた変更を上書きする傾向があります。どうやって知っているか聞いてください。
PostgreSQLでHibernateが 'serial'列を使用するようにするには、@GeneratedValue(strategy = GenerationType.IDENTITY)
を使用しなければならなかったことを思い出すようです。
GenerationType.AUTOの代わりに戦略GenerationType.IDENTITYを使用して@GeneratedId列を設定する必要があります。
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JUD_ID")
private Long _judId;
以前にも同じエラーが発生しました。データベースにこのクエリを入力してくださいCREATE SEQUENCE hibernate_sequence START WITH 1 INCREMENT BY 1 NOCYCLE;
それは私のために働いています、幸運〜
また、MySQLからPostgreSQLへの移行に関するいくつかのメモを追加したいと思います。
私が今覚えている限りでは、これらのヒントが試行錯誤の数分をあなたの手間を省くことを願っています!
あなたはすでに十分な答えを持っていると思いますが、私はまったく同じエラーを受け取り、私の問題は別のものでした。そして、それを解決しようとして少し時間を無駄にしました。
私の場合、問題は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;
誰にとっても役立つことを願っています。
GeneratedValue
およびGenericGenerator
を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;
Hibernateはデフォルトでそのようなシーケンスを検索するため、シーケンス呼び出しhibernate_sequence
を作成する必要がありました。
create sequence hibernate_sequence start with 1 increment by 50;
grant usage, select on all sequences in schema public to my_user_name;
Postgresを使用している場合、「hibernate_sequence」という名前のシーケンスを手動で作成します。それが動作します。
使用しているデータベースは、Postgres SQL設定ファイルのsearch_pathに記載する必要があります。これは、たとえばTESTDBなどのデータベース名とともにsearch_pathを設定して、Postgressql構成ファイルを編集することで実行できます。
上記の変更を行った後、私にとってはうまくいきました。