JPA EntityManager:を利用する理由が続く()以上の統合()?
-
21-08-2019 - |
質問
EntityManager.merge()
の挿入が可能で新たなオブジェクトの更新を設定しています。
なぜひ使いたい persist()
(できるだけ新しいオブジェクトを作成)?
解決
のPersistenceContextにエンティティを追加しますどちらにしても、違いは、その後エンティティに何をすべきかです。
は永続、エンティティインスタンスをとり、コンテキストに追加して、インスタンスを管理(エンティティにすなわち将来の更新が追跡される)ことになります。
マージは、エンティティの新しいインスタンスを作成し、コピー供給エンティティからの状態、および新しいコピーを管理します。あなたが渡すインスタンスは管理されません(あなたが行った変更は、トランザクションの一部ではありません - あなたは再びマージ呼び出さない限り)。
たぶんコード例は、役立ちます。
MyEntity e = new MyEntity();
// scenario 1
// tran starts
em.persist(e);
e.setSomeField(someValue);
// tran ends, and the row for someField is updated in the database
// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue);
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)
// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue);
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)
シナリオ1と3はほぼ同じですが、あなたはシナリオ2を使用したいと思い、いくつかの状況があります。
他のヒント
が続く場合は二つの異なる目的ではない選択肢であります。
(編集の拡大差情報)
persist:
- Insert新規登録、データベース
- 添付のオブジェクトの企業に対す。
統合:
- 見添付オブジェクトと同じidを更新します。
- が存在する更新をすでに所属しているオブジェクトです。
- の場合は存在しないの挿入を新規登録のデータベースです。
持続()効率:
- この効率化を挿入するための新規登録データベースへのより統合().
- な複製元のオブジェクトです。
持続()セマンティクス
- される可能性があるためです。いることを挿入しない更新するものとします。
例:
{
AnyEntity newEntity;
AnyEntity nonAttachedEntity;
AnyEntity attachedEntity;
// Create a new entity and persist it
newEntity = new AnyEntity();
em.persist(newEntity);
// Save 1 to the database at next flush
newEntity.setValue(1);
// Create a new entity with the same Id than the persisted one.
AnyEntity nonAttachedEntity = new AnyEntity();
nonAttachedEntity.setId(newEntity.getId());
// Save 2 to the database at next flush instead of 1!!!
nonAttachedEntity.setValue(2);
attachedEntity = em.merge(nonAttachedEntity);
// This condition returns true
// merge has found the already attached object (newEntity) and returns it.
if(attachedEntity==newEntity) {
System.out.print("They are the same object!");
}
// Set 3 to value
attachedEntity.setValue(3);
// Really, now both are the same object. Prints 3
System.out.println(newEntity.getValue());
// Modify the un attached object has no effect to the entity manager
// nor to the other objects
nonAttachedEntity.setValue(42);
}
このようにのみ存在する1添付オブジェクトの他の登録、企業マネージャ。
合併)を主体とidのようなもの:
AnyEntity myMerge(AnyEntity entityToSave) {
AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
if(attached==null) {
attached = new AnyEntity();
em.persist(attached);
}
BeanUtils.copyProperties(attached, entityToSave);
return attached;
}
が接続された場合にはMySQLの合併に()がして効率的として持続()を呼び出しを挿入しON DUPLICATE KEY UPDATEオプションJPA会員企業は非常に高いレベルのプログラミングできないと私たちの社会における音楽の場合です。
だが、割り当てられた発電機 を合併しなく続く原因となり、冗長化されたSQL文, な影響を与えます。
また、 呼び出し統合のための管理体 も間違いて管理主体が自動的に管理し、Hibernateやその状態を同期させたデータベースに dirtyチェック機構 受 フラッシングの永続化の文脈.
いかにしてこの作品は、まず最初に知ることHibernateシフトの開発マインドからのSQLステートメントを 体の状態遷移.
一企業が積極的に管理し、Hibernateは、すべての変更を自動的に伝播するデータベースです。
Hibernateのモニター付属機関となった。が主体にな管理が必要ですの権利主体の状態です。
まず、必要なのは、定義の全体の状態:
新しい過渡)
新しく作成されたオブジェクトとなって、Hibernate
Session
(a.k.aPersistence Context
のではありませんマップされた任意のデータベーステーブル列しているものとみなされるの過渡状態になります。な続きをする必要があり明示的に呼び出さ
EntityManager#persist
方法をご利用いただけ推移的な永続化機構。永続的な管理の
持続的な企てに関連するデータベースのテーブル列で管理されている現在の走り続コンテキスト更な主体が検出され、伝播、データベース(セッション中のフラッシュ-時間)とHibernateしない行を挿入、更新-削除に関すHibernateを採用 取引の書き-背景 ワークスタイルの変化は同期されているので、担当の瞬間で、現在の
Session
フラッシュします。一戸建て
一度、現在の走り続コンテキストがすべての管理主体となる。を継続的に変化なくなる追跡と自動データベースの同期がだろう。
学外団体への活動、Hibernateのセッションでは、どちらかを選択してください以下のオプション:
再付着
HibernateはJPA2.1)支援を再付着のセッション#更新方法です。は、Hibernateのセッションできるだけ准一体オブジェクトの指定されたデータベースです。これは、永続化の文脈行為としてメモリキャッシュ(第レベルのキャッシュ)、値(エンティティ)に関連付けられた指定された鍵(エンティティタイプとデータベース識別子).企業再び装着させることができますのない場合のみその他のJVMオブジェクト(マッチングと同じデータベース行)すでに関連付けられている現在のHibernateのセッション。
融合
合併にはコピーの一戸建ての体の状態(出所)する管理体のインスタンス(destination).場合の合併にしかない現在のセッションでは、これから取得し、データベースです。の一戸建てのオブジェクトインスタンスは引き続き一戸建てのものが合併します。
除
はJPAを求める管理者のみが許されて除去し、Hibernateでも削除外事業体がみを通してセッション#削除方法けます。取団体での予定を削除が実際のデータベースを削除算する実行時のセッションフラッシュします。
を理解するJPA状態遷移より可視化できます以下の図:
またはご利用の場合は、Hibernateの特定のAPI:
私はem.merge
を使用したとき、私はJPAが私のために生成された何のフィールドがなかった場合でも、すべてのSELECT
用INSERT
文を得たことに気づきました。私はem.persist(myEntityObject)
に切り替え、その後、ちょうどINSERT
文を得ています。
JPA仕様では、persist()
については、以下の言います。
X は分離オブジェクトである場合に存続するとき、ときにオブジェクトがのデタッチ対象となるのではないはず、
EntityExistsException
がスローされてもよいです 操作が呼び出される、またはEntityExistsException
または別のPersistenceException
がフラッシュで投げても良いし、時間をコミットします。
だから、persist()
を使用することは適切であろう。あなたはそれが速く失敗したように、コードがPersistenceException
を投げる持つことを好むかもしれません。
、persist()
を設定することもできますオブジェクトの@GeneratedValue
の@Id
。 merge()
は、しかし、既に生成@Id
を持つオブジェクトを持っている必要があります。
merge
とpersist
の間にいくつかのより多くの違いが(私は再び、すでにここに掲載それらを列挙します)があります:
D1。 merge
は、渡されたエンティティが管理させるのではなく、管理されている別のインスタンスを返していません。反対側のpersist
が渡されたエンティティの管理になります。
//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);
//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);
D2。あなたは、エンティティを削除してから戻ってエンティティを永続化することを決定した場合merge
はIllegalArgumentException
がスローされますので、あなたが、)だけでは(存続することを行うことができます。
D3。あなたは(UUIDを使用することにより、例えば)あなたのIDの手動で世話をすることを決定した場合には、merge
SELECT
は、これらのクエリを必要としないかもしれないが、操作は、そのIDを持つ既存のエンティティを探すために、後続のpersist
クエリをトリガします。
D4。あなたは、単に何もデータが更新されていないのではなく、挿入されて、あなたはpersist
を使用しなければならないことを確認するためにあなたのコードを呼び出すコードを信頼し、していないときケースがあります。
マージ使用するのに役立ちますマージに関するいくつかの詳細は以上持続します:
元のエンティティ以外の管理インスタンスを返すマージの重要な一部であり、 処理する。同じ識別子を有するエンティティのインスタンスが既に永続コンテキストに存在する場合、 プロバイダがマージされますが、管理されているエンティティの状態と、その状態が上書きされます それは使用することができるように、すでに存在していたバージョンがクライアントに返さなければなりません。プロバイダがなかった場合は 永続コンテキストにEmployeeインスタンスを更新し、そのインスタンスへの参照になるだろう マージされ、新しい状態と矛盾します。
マージ()が新しいエンティティに呼び出されると、は、持続()操作と同様に振る舞います。これは、追加されます 永続コンテキストにエンティティが、その代わりに、元のエンティティインスタンスを追加するには、それは新しいを作成し、 コピーして、そのインスタンスを管理します。マージ()操作によって作成されたコピーが保持されます 持続()メソッドが呼び出されたかのように。
関係の存在下で、マージ()操作は、管理対象エンティティを更新しようとします 切り離されたエンティティが参照するエンティティの管理のバージョンを指すようにします。実体がある場合は 永続的なアイデンティティを持っていないオブジェクトとの関係は、マージ操作の結果は、 未定義。一部のプロバイダは、管理対象のコピーを非永続オブジェクトを指すようにできる可能性があります、 他の人がすぐに例外をスローする可能性があるのに対し。マージ()オペレーションは、任意とすることができます 発生から例外を防ぐために、これらのケースでカスケード接続。我々は(マージのカスケードをカバーします) このセクションの後半で操作。エンティティが削除されたエンティティにマージされたポイントである場合は、 IllegalArgumentException例外がスローされます。
レイジーローディングリレーションシップは、マージ操作に特別なケースです。遅延ロードの場合 関係は、それが切り離されるようになった前に、エンティティにトリガされていなかった、その関係は次のようになります エンティティがマージされたときに無視されます。管理して、エンティティは外した間nullに設定しながら、関係がトリガされた場合には、企業の管理バージョンも同様にマージ中にクリアな関係を持つことになります。」
上記の情報はすべて、マイク・キースとメリックSchnicariolによる「プロJPA 2は、Java™永続化APIをマスター」から取られました。第6章節の剥離やマージ。この本は、実際に著者がJPAに捧げられた二冊目の本です。この新しい本は、多くの新しい情報前者を持っています。私は本当に真剣にJPAと関わることになるもののためにこの本を読むことを推薦します。私はanonimously私の最初の答えを投稿して申し訳ありません。
私は自分のエンティティで遅延読み込みの例外を得ていた。
私は、個別の要求にあった行うセッションからエンティティを取得し、問題があった私のjspページにコレクションにアクセスしようと何ます。
私が想像するが、私はセッションで再保存するとこれを軽減するために、私はSessionScope
ないがLazyLoadingException
、例の変形例を投げても、それはまた、アクセス可能になることを、私のコントローラで同じエンティティを更新し、私のjspにそれを渡します2:
以下は、私のために働いています:
// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"
//access e from jsp and it will work dandy!!
の回答が欠落に関してのカスケードやidます。 見る質問
ものであると言いましたが、できて Cascade
アノテーションの統合、根強い: Cascade.MERGE
や Cascade.PERSIST
する処理による使用法です。
どの仕様をご友人;)
ここからの説明があり、Hibernate docs啓発でが含まれている使用例:
の利用と意味論の融合()そうな混乱のための新しいユーザーまず、どんなを利用することにしたのだろうオブジェクトの状態で読み込むティマネージャーも新しい組織のマネージャーでは、すべ を使用する必要はなく統合()全ての.一部の全用途ないとはこのメソッドを使用します。
通常、統合()を使用して、以下のシナリオ:
- のアプリケーションオブジェクトの最初の体長
- のオブジェクトが渡され、プレゼンテーション層
- 一部の改変のオブジェクト
- のオブジェクトが渡された後のビジネスロジック層
- の応用が続くこれらの変更を呼び出し合えば、第二の体長
こちらではの正確な意味の統合():
- がある場合は、管理インスタンスが同じ識別子に現在関連付けられているの永続化の文脈で、コピーの状態を指定されたオブジェクトの管理インスタンス
- がない場合は管理インスタンスに現在関連付けられているの永続化の文脈で、負荷のかから、データベースに、新しい管理インスタンス
- の管理インスタンスが返される
- 指定されたインスタンスとなっていませんの持続性との関連では一戸建てであり、通常は破棄され
: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html
JPAグ大簡素化領域における企業 って作成されたアプリケーションのJavaプラットフォーム.メーカーとしての人た 対応の練の企業豆にJ2EEの 含JPA会員企業の中には、Java EE仕様として大きな飛躍 ます。しかし、深化にJPAを使用したプログラミング方法の詳細を見たい ことはよく分からないことがとても簡単です。この記事を取り扱うの比較 のEntityManagerの合が続くの方法が重複する 動作がする可能性があります混乱を引き起こすことだけでなく、留守.さらに私は を提案し一般化であることは両方の方法で特別な場合としての より一般的方法ます。
続事業体
とは対照的に統合法の継続の方法は非常に簡単で、直観的です。最も普通のシナリオの継続法の用途に使用することができまÿ
"新しく作成されたインスタンスエンティティの場合、このクラスが渡されたのが続く。このメソッドを返しまって、企業の管理および計画に挿入し、データベースです。で起こる前に取引を犯した場合にflushメソッドが呼び出されます。場合には実体参照他の事業体の関係に付いたので続くカスケード戦略にこの手順を適用します。"
の仕様がより詳しを覚えていないとして非常に重要であこれらの内容をカバー下のエキゾチックな状況です。
合体
との比較が続く中、記述の合併の行動はそれほど簡単ではない。ありませんメインシナリオは、そのままの場合は持続、プログラマは決して忘れてはいけないと思全てのシナリオを書くために正しいコードです。そのためにJPAデザイナーって何らかの方法が主要な懸念する取り扱い一戸建ての主体として反対側に続方法を扱う新規作成された団体ました。) の統合法の主要なタスクの状態からポリシー組織として渡される引数)を管理する国内の持続コンテキストこのタスクが割はさらに複数のシナリオの悪化を理解度の全体のメソッドの行動です。
の代わりに繰り返し項にJPA仕様が新しいフロー図を模式的に描いたの行動の統合方法:
なので、されることがあります。が続く場合?
持続
- いのメソッドは常に新しい主体とな更新する団体をいう。そうしないと、メソッドは例外をスローしますの結果として主キーの一意性の侵害となります。
- バッチプロセス、取扱い主体にステートフルに照Gatewayのパターン).
- パフォーマンスの最適化
統合
- いの方法のいずれかを挿入したは更新者のデータベースです。
- また取扱い事業体で国籍の方(データ転送物サービス)
- 挿入したい新しいる可能性がありますので、ご参照他の事業体であることができない恐れがある作られているので、その先からとの関係を特徴とするものでなければな合併).例えば、挿入-アクセサリーをプラスへの参照のどちらかの新規または既存のアルバム。
シナリオX:
表:Spitter(ワン)、表(多く)Spittles(SpittlesがFKとの関係の所有者である:spitter_id)
保存中にこのシナリオの結果:。Spitterとの両方Spittlesを同じSpitterが所有しているかのように
Spitter spitter=new Spitter();
Spittle spittle3=new Spittle();
spitter.setUsername("George");
spitter.setPassword("test1234");
spittle3.setSpittle("I love java 2");
spittle3.setSpitter(spitter);
dao.addSpittle(spittle3); // <--persist
Spittle spittle=new Spittle();
spittle.setSpittle("I love java");
spittle.setSpitter(spitter);
dao.saveSpittle(spittle); //<-- merge!!
シナリオY:
この2 Spittlesを保存します。しかし、彼らは同じSpitterを参照しないだろう、Spitterが保存されます!
Spitter spitter=new Spitter();
Spittle spittle3=new Spittle();
spitter.setUsername("George");
spitter.setPassword("test1234");
spittle3.setSpittle("I love java 2");
spittle3.setSpitter(spitter);
dao.save(spittle3); // <--merge!!
Spittle spittle=new Spittle();
spittle.setSpittle("I love java");
spittle.setSpitter(spitter);
dao.saveSpittle(spittle); //<-- merge!!
別の観測ます:
こうしたIDを持つレコードがすでにあなたのテーブルに存在する場合、 merge()
は、自動生成されたID(IDENTITY
とSEQUENCE
上でテスト)を気にします。その場合にはmerge()
は、レコードを更新しようとします。
しかし、idが存在しないか、または任意の既存のレコードに一致していない場合は、merge()
はそれを完全に無視して、新しいものを割り当てるようにデシベルを聞いてきます。これは時々、多くのバグの発生源です。新しいレコードのIDを強制的にmerge()
を使用しないでください。
persist()
は、あなたもそれにIDを通過させることは決してありません。それはすぐに失敗します。私の場合、それはです。
によって引き起こさ:org.hibernate.PersistentObjectException:独立エンティティ 存続するために渡されます。
休止状態-JPA Javadocはヒントがあります:
の の例外:javax.persistence.EntityExistsException - エンティティの場合 もう存在している。 (エンティティがすでに存在する場合は、 持続操作であるときEntityExistsExceptionがスローされます 呼び出された、またはEntityExistsExceptionまたは別のPersistenceException フラッシュまたはコミット時にスローされる可能性があります。)
いちのためのアドバイスを使用する場合 持続 とするために使用さ 統合.だと思うの状況:いかがでの作成を行う必要があり新記録となどができ続きデータです。
うにょご利用できるので、自然ートキーの識別子です。
データを残すものを記録が存在するデータを変更することが求められています。この場合にきてみて、持続を行う場するEntityExistsExceptionまうので、組み合わせのデータ
try{entityManager.持続(者)}
catch(EntityExistsException例外){/*取得する場合*/}
続きデータを更新する必要があるということが一度あのデータはまだない。この場合のお一見の価値ありで、いが続く場合、又は欠
体=entityManager.find(キー);
る場合(エンティティ==null){entityManager.持続(者);}
else{/*統合*/}
い自然のキーの識別子、いかどうかを、企業が存在しない、またはどのようにしました。
の合併することで処理されは二つの方法がありま
- 変更の場合は、通常、小型の管理団体をいう。
- 変化があった場合は、コピーを利用して次のように書き換えられ、保持団体など己責任にデータです。呼び出して、EntityManager::統合()に置き換えに古い内容です。
(実体はすでにDBに存在する場合EntityExistsException投げがあるでしょう)DBに追加し、全く新しいエンティティして使用する必要があります(エンティティ)を持続。
(エンティティ)をマージエンティティが剥離し、変更された場合、バック永続コンテキストにエンティティを置くために、使用されるべきである。
おそらく、INSERTのSQL文を生成し、UPDATEのSQL文をマージ(私はよく分からない)されて存続します。