したがって、プロジェクトではPostgreSQLデータベースを使用し、データベースの操作にはJPAを使用します。 Netbeans 7.1.2の自動作成者を使用して、データベースからエンティティを作成しました。
小さな変更後、主キーの値は次のように説明されます。
_@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Basic(optional = false)
@NotNull
@Column(name = "idwebuser", nullable = false)
private Integer idwebuser;
_
問題は、Java app-生成された値が実際のデータベースよりも低いので、データベースを直接変更するとき(SQLまたは別のツールを使用) ID値-したがって、新しいエンティティの作成中にエラーが発生します。
JPAがデータベースにIDを自動的に生成させ、作成プロセス後にIDを取得させる可能性はありますか?または、より良い解決策は何でしょうか?ありがとう。
[〜#〜] edit [〜#〜]より具体的には、ユーザーのテーブルがあり、私の問題は、任意のタイプの戦略生成タイプを使用して、JPAが指定されたジェネレーターIDです。新しいエントリを追加して自分でテーブルを変更すると、アプリケーションのGeneratedValueが現在のIDよりも低くなるため、IDが重複するという例外が発生するため、これは私にとって間違っています。修正できます;)?
答えに関する短いメモPG Admin->最初の100行を表示し、選択を使用する代わりにそこに。とにかく、このエディターは何らかの方法でIDの更新プロセスをスキップするため、適切なINSERTを記述するとDBでも不適切なIDで実行されます。したがって、基本的にはデータベースとアプリケーションよりも、使用したエディターの問題でした...
今では@GeneratedValue(strategy=GenerationType.IDENTITY)
を使用しても動作します
テーブル定義が与えられた場合:
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
という命名は、SERIAL
のPostgreSQLのデフォルトのシーケンス命名であり、これに従うことをお勧めします。
allocationSize=1
は、Hibernateがデータベースの他のクライアントと協力する必要がある場合に重要です。
トランザクションがロールバックする場合、このシーケンスには「ギャップ」があることに注意してください。トランザクションは、あらゆる種類の理由でロールバックできます。アプリケーションは、これに対処するように設計する必要があります。
n
にはID n-1
またはn+1
があると想定しないでくださいn
より小さいIDの前またはn
より大きいIDの後にn
という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
アノテーションを追加した理由の説明に役立つはずです。
ギャップのないシーケンス(チェックや請求書番号など)が本当に必要な場合は、 ギャップレスシーケンス を参照してください。ただし、真剣にこの設計を避け、neverで使用してください。主キー用。
注:テーブル定義が代わりにこのように見える場合:
CREATE TABLE webuser(
idwebuser integer primary key,
...
)
そして、(unsafeを使用してそれに挿入している、使用しないでください):
INSERT INTO webuser(idwebuser, ...) VALUES (
(SELECT max(idwebuser) FROM webuser)+1, ...
);
または(安全ではない、これを絶対に行わない):
INSERT INTO webuser(idwebuser, ...) VALUES (
(SELECT count(idwebuser) FROM webuser), ...
);
その後、あなたはそれを間違っています、シーケンスに切り替える必要があります(上記のように)またはロックされたカウンターテーブルを使用してcorrectギャップレスシーケンス実装に(再び、上記を参照し、Googleの「ギャップレスシーケンスpostgresql」を参照してください)。データベースで複数の接続が動作している場合、上記の両方とも間違った動作をします。
次のようなシーケンスジェネレータを使用する必要があるようです。
@GeneratedValue(generator="YOUR_SEQ",strategy=GenerationType.SEQUENCE)
GenerationType.TABLE
の代わりにGenerationType.IDENTITY
を使用してみてください。データベースは、一意の主キーを生成するために使用される別のテーブルを作成し、最後に使用されたID番号も保存します。
それは私のために働く
CREATE TABLE webuser(
idwebuser SERIAL PRIMARY KEY,
...
)
@Entity
@Table(name="webuser")
class Webuser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// ....
}
また、一般的なGenerationType.IDENTITY
を選択した回答によって提案されたソリューションに大量に変換するスクリプトを記述することで、労力を節約できます。以下のスクリプトは、Javaソースファイルのフォーマット方法に若干の依存関係があり、バックアップなしで変更を行います。
スクリプトを実行した後:
import javax.persistence.Table;
を検索してimport javax.persistence.Table; import javax.persistence.SequenceGenerator;
に置き換えます。次のスクリプトをupdate-sequences.sh
または同様の名前で保存します。
#!/bin/bash
# Change this to the directory name (package name) where the entities reside.
PACKAGE=com/domain/project/entities
# Change this to the path where the Java source files are located.
cd src/main/Java
for i in $(find $PACKAGE/*.Java -type f); do
# Only process classes that have an IDENTITY sequence.
if grep "GenerationType.IDENTITY" $i > /dev/null; then
# Extract the table name line.
LINE_TABLE_NAME=$(grep -m 1 @Table $i | awk '{print $4;}')
# Trim the quotes (if present).
TABLE_NAME=${LINE_TABLE_NAME//\"}
# Trim the comma (if present).
TABLE_NAME=${TABLE_NAME//,}
# Extract the column name line.
LINE_COLUMN_NAME=$(grep -m 1 -C1 -A3 @Id $i | tail -1)
COLUMN_NAME=$(echo $LINE_COLUMN_NAME | awk '{print $4;}')
COLUMN_NAME=${COLUMN_NAME//\"}
COLUMN_NAME=${COLUMN_NAME//,}
# PostgreSQL sequence name.
SEQUENCE_NAME="${TABLE_NAME}_${COLUMN_NAME}_seq"
LINE_SEQ_GENERATOR="@SequenceGenerator( name = \"$SEQUENCE_NAME\", sequenceName = \"$SEQUENCE_NAME\", allocationSize = 1 )"
LINE_GENERATED_VAL="@GeneratedValue( strategy = GenerationType.SEQUENCE, generator = \"$SEQUENCE_NAME\" )"
LINE_COLUMN="@Column( name = \"$COLUMN_NAME\", updatable = false )\n"
# These will depend on source code formatting.
DELIM_BEGIN="@GeneratedValue( strategy = GenerationType.IDENTITY )"
# @Basic( optional = false ) is also replaced.
DELIM_ENDED="@Column( name = \"$COLUMN_NAME\" )"
# Replace these lines...
#
# $DELIM_BEGIN
# $DELIM_ENDED
#
# With these lines...
#
# $LINE_SEQ_GENERATOR
# $LINE_GENERATED_VAL
# $LINE_COLUMN
sed -i -n "/$DELIM_BEGIN/{:a;N;/$DELIM_ENDED/!ba;N;s/.*\n/$LINE_SEQ_GENERATOR\n$LINE_GENERATED_VAL\n$LINE_COLUMN/};p" $i
else
echo "Skipping $i ..."
fi
done
NetBeansを使用してCRUDアプリケーションを生成する場合、ID属性には編集可能な入力フィールドは含まれません。