HibernateがスローしたNonUniqueObjectException
に問題があります。
ドキュメントと this ブログ投稿を読んで、update()
からmerge()
への呼び出しを置き換え、問題を解決しました。
切断されたオブジェクトとセッションの境界に関して、例外の理由と、メソッドを変更すると問題が解決した理由を理解していると思います。
私の質問は:merge()
は常にセッションオブジェクトに解決するか、存在しない場合はそれを取得するため、一般にupdate()
よりも安全なmerge()を呼び出していますか?
merge()
よりもupdate()
を使用する場合の欠点は何ですか?
通常、merge()の呼び出しはupdate()より安全な代替手段ですか?
NonUniqueObjectExceptionを回避する方法として、はい。 JPAが更新メソッドを許可しない理由を説明していると思います。
Update()よりもmerge()を使用することの欠点は何ですか?
助言されていないユーザーは、彼または彼女が新しい管理されたエンティティを持っていると思うかもしれません。何かのようなもの
// myEntity (passed as parameter does not become managed)
// Only the one returned by the merge operation is a managed entity
session.merge(myEntity);
// "newValue" is not commited because myEntity is not managed
myEntity.setMyProperty("newValue");
また、永続コンテキストにエンティティが含まれていない場合、select-before-updatingのデフォルトの動作が不要になる可能性があります。しかしそれは避けられます
...
public void updateMyEntity(MyEntity updateableMyEntity);
// load does not hit the database
MyEntity myEntity = (MyEntity) session.load(MyEntity.class, updateableMyEntity.getId());
BeanUtils.copyProperties(myEntity, updateableMyEntity);
}
このようにして、マージまたは更新メソッドなしでエンティティを更新できます。詳細については、この質問を参照してください。 Hibernateでデタッチされたオブジェクトの一部のフィールドを更新する最良の方法?
セッションに同じ識別子の永続インスタンスが含まれていないことが確実な場合はupdate()を使用し、セッションの状態を考慮せずにいつでも変更をマージする場合はmerge()を使用します。言い換えると、通常、update()は、デタッチされたインスタンスの再アタッチが最初に実行される操作であることを確認して、新しいセッションで呼び出す最初のメソッドです。
_SessionFactory factory = cfg.buildSessionFactory();
Session session1 = factory.openSession();
Student s1 = null;
Object o = session1.get(Student.class, new Integer(101));
s1 = (Student)o;
session1.close();
s1.setMarks(97);
Session session2 = factory.openSession();
Student s2 = null;
Object o1 = session2.get(Student.class, new Integer(101));
s2 = (Student)o1;
Transaction tx=session2.beginTransaction();
session2.merge(s1);
_
説明
行番号4〜7からわかるように、1つのオブジェクトs1をsession1キャッシュにロードし、行番号7でsession1を閉じたので、session1キャッシュのオブジェクトs1は破棄されます。これは、session1.close()
。
これで、s1オブジェクトは、RAMの場所にあり、session1キャッシュにはありません。ここでs1は切り離された状態にあり、行番号8で、切り離されたオブジェクトs1を変更します。update()
メソッドの場合、オブジェクトはセッションでのみ更新できるため、hibernateはエラーをスローします。
そこで、行番号10で別のセッション[session2]を開き、データベースから同じ学生オブジェクトをs2という名前で再度ロードしました。したがって、このセッション2では、session2.merge(s1);
を呼び出してs2オブジェクトに入れます。s1の変更はマージされ、データベースに保存されます