43

そのため、私たちのプロジェクトでは PostgreSQL データベースを使用し、データベースの操作には JPA を使用しています。Netbeans 7.1.2 の自動作成機能を使用して、データベースからエンティティを作成しました。

小さな変更の後、主キーの値は次のように記述されます。

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Basic(optional = false)
@NotNull
@Column(name = "idwebuser", nullable = false)
private Integer idwebuser;

問題は、アプリケーションが柔軟でないことです。これは、Java アプリを使用する代わりに (SQL または別のツールを使用して) データベースを直接変更すると、生成された値が実際のデータベース ID 値よりも低くなり、実行中にエラーが発生するためです。新しいエンティティの作成。

JPAがデータベースにIDを自動的に生成させ、作成プロセス後に取得できる可能性はありますか? または、より良い解決策は何ですか?ありがとう。

EDIT より具体的には、ユーザーのテーブルがあり、私の問題は、任意のタイプの戦略生成タイプを使用して、JPA がそのジェネレーター ID で指定された新しいエンティティを挿入していることです。新しいエントリを追加して自分でテーブルに変更を加えると、アプリケーションの GeneratedValue が現在の ID よりも低くなり、ID が重複して例外が発生するため、これは間違っています。修正できますか ;)?

答えに関する簡単なメモ PG Admin -> View first 100 Rows を使用し、select を使用する代わりにそこから行を編集したため、私の側から少し嘘がありました。いずれにせよ、このエディターは ID の更新プロセスを何らかの形でスキップすることが判明したため、DB でも適切な INSERT を記述しても、不適切な ID で実行されます! つまり、基本的には、データベースとアプリケーションよりも、使用したエディターの問題でした...

今でもそれを使用して動作します@GeneratedValue(strategy=GenerationType.IDENTITY)

4

5 に答える 5

86

テーブル定義が与えられた場合:

CREATE TABLE webuser(
    idwebuser SERIAL PRIMARY KEY,
    ...
)

マッピングを使用します。

@Entity
@Table(name="webuser")
class Webuser {

    @Id
    @SequenceGenerator(name="webuser_idwebuser_seq",
                       sequenceName="webuser_idwebuser_seq",
                       allocationSize=1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
                    generator="webuser_idwebuser_seq")
    @Column(name = "idwebuser", updatable=false)
    private Integer id;

    // ....

}

ネーミングtablename_columname_seqは PostgreSQL のデフォルト シーケンス ネーミングでSERIALあり、それに固執することをお勧めします。

これallocationSize=1は、Hibernate がデータベースに対して他のクライアントと連携する必要がある場合に重要です。

トランザクションがロールバックする場合、このシーケンスには「ギャップ」があることに注意してください。トランザクションは、あらゆる種類の理由でロールバックする可能性があります。アプリケーションは、これに対処するように設計する必要があります。

  • 任意の idnに idn-1またはn+1
  • nidが より小さい id の前nまたは より大きい id の後に追加またはコミットされたと想定しないでくださいn。シーケンスの使用方法に本当に注意している場合は、これを行うことができますが、決して試してはいけません。代わりにテーブルにタイムスタンプを記録してください。
  • ID に追加したり、ID から削除したりしないでください。それらを比較して、同等であるかどうかを比較します。

シーケンスシリアル データ型については、PostgreSQL のドキュメントを参照してください。

彼らは、上記のテーブル定義は基本的に次のショートカットであると説明しています。

CREATE SEQUENCE idwebuser_id_seq;
CREATE TABLE webuser(
    idwebuser integer primary key default nextval('idwebuser_id_seq'),
    ...
)
ALTER SEQUENCE idwebuser_id_seq OWNED BY webuser.idwebuser;

@SequenceGenerator...これは、シーケンスを説明するために注釈を追加した理由を説明するのに役立ちます。


本当にギャップのないシーケンス (小切手や請求書の番号付​​けなど)が必要な場合は、ギャップのないシーケンスを参照してください。


: テーブル定義が次のようになっている場合:

CREATE TABLE webuser(
    idwebuser integer primary key,
    ...
)

そして、(安全でない、使用しないでください)を使用してそれに挿入しています:

INSERT INTO webuser(idwebuser, ...) VALUES ( 
    (SELECT max(idwebuser) FROM webuser)+1, ...
);

または(安全でない、これをしないでください):

INSERT INTO webuser(idwebuser, ...) VALUES ( 
    (SELECT count(idwebuser) FROM webuser), ...
);

その場合、あなたはそれを間違っているので、シーケンス (上記のように) に切り替えるか、ロックされたカウンター テーブルを使用して正しいギャップレス シーケンスの実装に切り替える必要があります (上記と Google の「ギャップレス シーケンス pos​​tgresql」を参照してください)。データベースで複数の接続が動作している場合、上記の両方が間違ったことを行います。

于 2012-08-06T12:19:49.887 に答える
2

次のようなシーケンスジェネレーターを使用する必要があるようです:

@GeneratedValue(generator="YOUR_SEQ",strategy=GenerationType.SEQUENCE)
于 2012-08-06T11:17:44.960 に答える
1

GenerationType.TABLEの代わりに使ってみてくださいGenerationType.IDENTITY。データベースは、一意の主キーを生成するために使用される別のテーブルを作成し、最後に使用された ID 番号も格納します。

于 2012-08-06T09:40:42.393 に答える