回答:
ここに私の方法の理解があります。これらはすべてAPIに基づいていますが、実際にはすべてを使用しているわけではありません。
saveOrUpdate いくつかのチェックに応じて、保存または更新を呼び出します。たとえば、識別子が存在しない場合、saveが呼び出されます。それ以外の場合は、更新が呼び出されます。
エンティティを永続化します。存在しない場合は識別子を割り当てます。ある場合、それは本質的に更新を行っています。エンティティの生成されたIDを返します。
update 既存の識別子を使用してエンティティの永続化を試みます。識別子が存在しない場合、例外がスローされると思います。
saveOrUpdateCopy これは非推奨であり、今後は使用しないでください。代わりに...
merge これで、私の知識が揺らぎ始めます。ここで重要なのは、一時的なエンティティ、分離されたエンティティ、永続的なエンティティの違いです。オブジェクトの状態の詳細については、こちらをご覧ください。保存と更新を使用すると、永続オブジェクトを処理できます。それらはセッションにリンクされているため、Hibernateは変更点を認識します。ただし、一時オブジェクトがある場合は、セッションは含まれません。これらの場合、更新にはマージを使用し、保存するには永続化する必要があります。
持続 としては、上述した、これは一過性のオブジェクトに使用されます。生成されたIDは返しません。
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║ METHOD ║ TRANSIENT ║ DETACHED ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ sets id if doesn't ║ sets new id even if object ║
║ save() ║ exist, persists to db, ║ already has it, persists ║
║ ║ returns attached object ║ to DB, returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ sets id on object ║ throws ║
║ persist() ║ persists object to DB ║ PersistenceException ║
║ ║ ║ ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ ║ ║
║ update() ║ Exception ║ persists and reattaches ║
║ ║ ║ ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ copy the state of object in ║ copy the state of obj in ║
║ merge() ║ DB, doesn't attach it, ║ DB, doesn't attach it, ║
║ ║ returns attached object ║ returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ ║ ║
║saveOrUpdate()║ as save() ║ as update() ║
║ ║ ║ ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
update
一時的なオブジェクトは問題ありませんが、例外は発生しませんでした。
永続化と保存の微妙な違いについては、Hibernateフォーラムを参照してください。違いは、INSERTステートメントが最終的に実行される時間です。以来、保存が識別子を返しません、INSERT文は関係なく、(一般的に悪いことである)トランザクションの状態を即座に実行する必要があります。Persistは、識別子を割り当てるためだけに、現在実行中のトランザクションの外部でステートメントを実行しません。Save / Persistはどちらも一時的なインスタンスで機能します。つまり、まだ識別子が割り当てられていないインスタンスであり、DBに保存されません。
更新とマージはどちらも分離されたインスタンス、つまりDBに対応するエントリがあるが、現在セッションに接続されていない(またはセッションによって管理されていない)インスタンスで機能します。それらの違いは、関数に渡されるインスタンスに何が起こるかです。updateはインスタンスを再アタッチしようとします。つまり、現在、セッションにアタッチされている永続エンティティの他のインスタンスがあってはなりません。それ以外の場合は、例外がスローされます。ただし、mergeは、すべての値をセッションの永続インスタンスにコピーするだけです(現在ロードされていない場合はロードされます)。入力オブジェクトは変更されません。したがって、マージは更新よりも一般的です、しかしより多くのリソースを使用する可能性があります。
save() - If an INSERT has to be executed to get the identifier, then this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is problematic in a long-running conversation with an extended Session/persistence context.
挿入がセッション外でどのように発生するのか、そしてなぜそれが悪いのか教えてください。
INSERT
編集されるときにDBによって生成されます。したがって、それらの場合、識別子を生成せずにすぐに識別子を返すことはできません。生成するには、INSERT
今すぐ実行する必要があります。長期実行トランザクションは現在実行されておらず、コミット時にのみ実行されるため、INSERT
今実行する唯一の方法は、txの外部で実行することです。
このリンクは良い方法で説明しています:
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
私たち全員が遭遇する問題はごくまれであり、それらをもう一度見ると、私たちはこれを解決したことを知っていますが、その方法を思い出せません。
HibernateでSession.saveOrUpdate()を使用したときにスローされるNonUniqueObjectExceptionは、私の例外です。複雑なアプリケーションに新しい機能を追加します。私のユニットテストはすべてうまくいきます。次に、UIをテストしてオブジェクトを保存しようとすると、「同じ識別子の値を持つ別のオブジェクトがすでにセッションに関連付けられています」というメッセージが表示されて例外が発生し始めます。これは、Hibernateを使用したJava Persistenceからのコード例です。
Session session = sessionFactory1.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
tx.commit();
session.close(); // end of first session, item is detached
item.getId(); // The database identity is "1234"
item.setDescription("my new description");
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Item item2 = (Item) session2.get(Item.class, new Long(1234));
session2.update(item); // Throws NonUniqueObjectException
tx2.commit();
session2.close();
この例外の原因を理解するには、デタッチされたオブジェクトと、デタッチされたオブジェクトでsaveOrUpdate()(または単にupdate())を呼び出すとどうなるかを理解することが重要です。
個々のHibernateセッションを閉じると、操作している永続オブジェクトが切り離されます。つまり、データはまだアプリケーションのメモリにありますが、Hibernateはオブジェクトへの変更を追跡する責任を負いません。
次に、デタッチされたオブジェクトを変更して更新したい場合は、オブジェクトを再アタッチする必要があります。その再接続プロセス中に、Hibernateは同じオブジェクトの他のコピーがあるかどうかを確認します。見つかった場合は、「実際の」コピーが何であるかがわからないことを通知する必要があります。おそらく、他のコピーが保存されると予想される他の変更が加えられた可能性がありますが、Hibernateはそれらを管理していなかったため、それらについては知りません。
Hibernateは、問題のある可能性のあるデータを保存するのではなく、NonUniqueObjectExceptionを介して問題を通知します。
それで、私たちは何をすべきですか?Hibernate 3にはmerge()があります(Hibernate 2ではsaveOrUpdateCopy()を使用)。このメソッドは、Hibernateが他のデタッチされたインスタンスから保存するインスタンスに変更をコピーするように強制します。したがって、保存する前にメモリ内のすべての変更をマージします。
Session session = sessionFactory1.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
tx.commit();
session.close(); // end of first session, item is detached
item.getId(); // The database identity is "1234"
item.setDescription("my new description");
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Item item2 = (Item) session2.get(Item.class, new Long(1234));
Item item3 = session2.merge(item); // Success!
tx2.commit();
session2.close();
mergeがインスタンスの新しく更新されたバージョンへの参照を返すことに注意することが重要です。セッションにアイテムを再アタッチするわけではありません。インスタンスの等価性(item == item3)をテストすると、この場合はfalseを返します。この時点から、おそらくitem3で作業したいと思うでしょう。
また、Java Persistence API(JPA)には、デタッチされたオブジェクトと再アタッチされたオブジェクトの概念がなく、EntityManager.persist()とEntityManager.merge()を使用することに注意することも重要です。
一般的に、Hibernateを使用する場合、通常はsaveOrUpdate()で十分です。通常、同じタイプのオブジェクトへの参照を持つことができるオブジェクトがある場合にのみ、マージを使用する必要があります。最近、例外の原因は、参照が再帰的でないことを検証するコードにありました。検証の一部として同じオブジェクトをセッションにロードしていたため、エラーが発生しました。
この問題はどこで発生しましたか?マージは機能しましたか、それとも別のソリューションが必要でしたか?常にマージを使用するか、特定のケースで必要な場合にのみ使用するか
実際には、休止状態save()
とpersist()
メソッドの違いは、使用しているジェネレータークラスによって異なります。
ジェネレータークラスが割り当てられている場合、save()
およびpersist(
)メソッドの間に違いはありません。ジェネレーターは「割り当てられた」という意味なので、プログラマーとして、データベースに保存する主キーの値を指定する必要があります[このジェネレーターの概念を知っていることを願ってください]割り当てられたジェネレータークラス以外の場合、ジェネレータークラス名がIncrement hibernate it selfは、プライマリキーID値をデータベースに割り当てます[割り当てられたジェネレータ以外は、hibernateはプライマリキーID値を記憶するためにのみ使用されます]。このため、このメソッドsave()
またはを呼び出すpersist()
と、レコードがデータベースは通常ですが、聞くと、 save()
メソッドはhibernateによって生成された主キーID値を返すことができます。
long s = session.save(k);
この同じケースでpersist()
は、クライアントに値を返すことはありません。
すべての休止状態の保存方法の違いを示す良い例を見つけました。
http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example
簡単に言えば、上記のリンクによると:
保存する()
persist()
saveOrUpdate()
トランザクションの有無にかかわらず使用できます。save()と同様に、トランザクションなしで使用した場合、マップされたエンティティは保存されません。セッションをフラッシュする必要はありません。
提供されたデータに基づいて、クエリを挿入または更新する結果。データがデータベースに存在する場合、更新クエリが実行されます。
更新()
マージ()
これらすべての実際の例については、上記のリンクを参照してください。これらのさまざまな方法の例が示されています。
この記事で説明したように、ほとんどの場合はJPAメソッドを使用しupdate
、バッチ処理タスクにはを使用する必要があります。
JPAまたはHibernateエンティティは、次の4つの状態のいずれかになります。
ある状態から別の状態への遷移は、EntityManagerまたはSessionメソッドを介して行われます。
たとえば、JPA EntityManager
は次のエンティティ状態遷移メソッドを提供します。
Hibernate Session
はすべてのJPA EntityManager
メソッドを実装しsave
、saveOrUpdate
およびのようないくつかの追加のエンティティ状態遷移メソッドを提供しますupdate
。
エンティティの状態をTransient(New)からManaged(Persisted)に変更するにはpersist
、JPA EntityManager
が提供するメソッドを使用できますSession
。これはHibernateにも継承されます。
この
persist
メソッドPersistEvent
は、DefaultPersistEventListener
Hibernateイベントリスナーによって処理されるをトリガーします。
したがって、次のテストケースを実行すると、
doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
LOGGER.info(
"Persisting the Book entity with the id: {}",
book.getId()
);
});
Hibernateは次のSQLステートメントを生成します。
CALL NEXT VALUE FOR hibernate_sequence
-- Persisting the Book entity with the id: 1
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
エンティティが現在の永続コンテキストid
にアタッチされる前にが割り当てられていることに注意してくださいBook
。これは、管理対象エンティティがMap
キーがエンティティタイプとその識別子で構成され、値がエンティティ参照である構造に格納されているために必要です。これが、JPA EntityManager
とHibernate Session
が一次キャッシュとして知られている理由です。
を呼び出すpersist
と、エンティティは現在実行中の永続コンテキストにのみアタッチされ、INSERTは、flush
が呼び出される。
唯一の例外は、エンティティ識別子を取得できる唯一の方法であるため、すぐにINSERTをトリガーするIDENTITYジェネレーターです。このため、HibernateはIDENTITYジェネレーターを使用してエンティティのバッチ挿入を行うことができません。このトピックの詳細については、チェックアウトしてくださいこちらの記事を。
Hibernate固有のsave
メソッドはJPAよりも古く、Hibernateプロジェクトの開始以来利用可能でした。
この
save
メソッドSaveOrUpdateEvent
は、DefaultSaveOrUpdateEventListener
Hibernateイベントリスナーによって処理されるをトリガーします。したがって、このsave
メソッドはupdate
およびsaveOrUpdate
メソッドと同等です。
save
メソッドの動作を確認するには、次のテストケースを検討してください。
doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
Session session = entityManager.unwrap(Session.class);
Long id = (Long) session.save(book);
LOGGER.info(
"Saving the Book entity with the id: {}",
id
);
});
上記のテストケースを実行すると、Hibernateは次のSQLステートメントを生成します。
CALL NEXT VALUE FOR hibernate_sequence
-- Saving the Book entity with the id: 1
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
ご覧のとおり、結果はpersist
メソッド呼び出しと同じです。ただし、とは異なりpersist
、save
メソッドはエンティティ識別子を返します。
詳しくは、こちらの記事をご覧ください。。
Hibernate固有のupdate
メソッドは、ダーティーチェックメカニズムをバイパスし、フラッシュ時にエンティティを強制的に更新することを目的としています。
この
update
メソッドSaveOrUpdateEvent
は、DefaultSaveOrUpdateEventListener
Hibernateイベントリスナーによって処理されるをトリガーします。したがって、このupdate
メソッドはsave
およびsaveOrUpdate
メソッドと同等です。
update
メソッドがどのように機能するかを確認するために、Book
エンティティを1つのトランザクションで永続化する次の例を検討し、エンティティが分離された状態にある間にそれを変更し、update
メソッド呼び出しを使用してSQL UPDATEを強制します。
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
LOGGER.info("Modifying the Book entity");
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.update(_book);
LOGGER.info("Updating the Book entity");
});
上記のテストケースを実行すると、Hibernateは次のSQLステートメントを生成します。
CALL NEXT VALUE FOR hibernate_sequence
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
-- Modifying the Book entity
-- Updating the Book entity
UPDATE
book
SET
author = 'Vlad Mihalcea',
isbn = '978-9730228236',
title = 'High-Performance Java Persistence, 2nd edition'
WHERE
id = 1
UPDATE
は、永続化コンテキストのフラッシュ中に、コミットの直前に実行されることに注意してください。そのため、Updating the Book entity
メッセージが最初にログに記録されます。
@SelectBeforeUpdate
して不要な更新を回避するこれで、エンティティがデタッチされた状態で変更されなかった場合でも、UPDATEは常に実行されます。これを防ぐには、フェッチし@SelectBeforeUpdate
たSELECT
ステートメントをトリガーするHibernateアノテーションを使用できます。loaded state
は、使用して、ダーティチェックメカニズムで。
したがって、Book
エンティティに注釈を付けると、次のようになります@SelectBeforeUpdate
。
@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {
//Code omitted for brevity
}
次のテストケースを実行します。
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.update(_book);
});
Hibernateは次のSQLステートメントを実行します。
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
SELECT
b.id,
b.author AS author2_0_,
b.isbn AS isbn3_0_,
b.title AS title4_0_
FROM
book b
WHERE
b.id = 1
UPDATE
Hibernateダーティチェックメカニズムがエンティティが変更されていないことを検出したため、今回は何も実行されないことに注意してください。
Hibernate固有のsaveOrUpdate
メソッドは、save
およびの単なるエイリアスですupdate
。
この
saveOrUpdate
メソッドSaveOrUpdateEvent
は、DefaultSaveOrUpdateEventListener
Hibernateイベントリスナーによって処理されるをトリガーします。したがって、このupdate
メソッドはsave
およびsaveOrUpdate
メソッドと同等です。
これでsaveOrUpdate
、エンティティを永続化する場合、またはUPDATE
次の例に示すようにを強制する場合に使用できます。
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(book);
return book;
});
_book.setTitle("High-Performance Java Persistence, 2nd edition");
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(_book);
});
NonUniqueObjectException
起こり得る一つの問題save
、update
およびsaveOrUpdate
永続コンテキストが既に次の例のように同一のIDを持つと同じタイプのエンティティ参照が含まれている場合です。
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(book);
return book;
});
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
try {
doInJPA(entityManager -> {
Book book = entityManager.find(
Book.class,
_book.getId()
);
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(_book);
});
} catch (NonUniqueObjectException e) {
LOGGER.error(
"The Persistence Context cannot hold " +
"two representations of the same entity",
e
);
}
ここで、上記のテストケースを実行すると、Hibernateはをスローします。NonUniqueObjectException
これは、2番目に、渡したものと同じ識別子のエンティティがEntityManager
既に含まれており、永続コンテキストが同じエンティティの2つの表現を保持できないためです。Book
update
org.hibernate.NonUniqueObjectException:
A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)
を回避するNonUniqueObjectException
にはmerge
、JPAが提供EntityManager
し、Hibernate Session
も継承したメソッドを使用する必要があります。
この記事で説明したようmerge
に、永続コンテキストにエンティティ参照が見つからない場合、はデータベースから新しいエンティティスナップショットをフェッチし、merge
メソッドに渡された分離されたエンティティの状態をコピーします。
この
merge
メソッドMergeEvent
は、DefaultMergeEventListener
Hibernateイベントリスナーによって処理されるをトリガーします。
merge
メソッドがどのように機能するかを確認するためにBook
、1つのトランザクションでエンティティを永続化する次の例を検討します。次に、エンティティが分離された状態にある間にエンティティを変更し、分離さmerge
れたエンティティをサブシーケンスの永続コンテキストに渡します。
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
LOGGER.info("Modifying the Book entity");
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
doInJPA(entityManager -> {
Book book = entityManager.merge(_book);
LOGGER.info("Merging the Book entity");
assertFalse(book == _book);
});
上記のテストケースを実行すると、Hibernateは次のSQLステートメントを実行しました。
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
-- Modifying the Book entity
SELECT
b.id,
b.author AS author2_0_,
b.isbn AS isbn3_0_,
b.title AS title4_0_
FROM
book b
WHERE
b.id = 1
-- Merging the Book entity
UPDATE
book
SET
author = 'Vlad Mihalcea',
isbn = '978-9730228236',
title = 'High-Performance Java Persistence, 2nd edition'
WHERE
id = 1
によって返されるエンティティ参照はmerge
、merge
メソッドに渡した分離されたものとは異なることに注意してください。
ここでmerge
、分離されたエンティティの状態をコピーする場合はJPAを使用することをお勧めしますがSELECT
、バッチ処理タスクを実行する場合は余分な問題が発生する可能性があります。
このため、update
現在実行中の永続コンテキストにすでにアタッチされているエンティティ参照がないこと、および切り離されたエンティティが変更されていることを確認してから使用することをお勧めします。
このトピックの詳細については、こちらの記事をご覧ください。
エンティティを永続化するには、JPA persist
メソッドを使用する必要があります。分離されたエンティティの状態をコピーするにmerge
は、優先する必要があります。このupdate
メソッドは、バッチ処理タスクにのみ役立ちます。save
とsaveOrUpdate
にちょうど別名であるupdate
、あなたは、おそらくすべてでそれらを使用しないでください。
一部の開発save
者は、エンティティがすでに管理されている場合でも呼び出しますが、これは誤りであり、管理対象エンティティの場合、UPDATEは永続コンテキストのフラッシュ時に自動的に処理されるため、冗長なイベントをトリガーします。
詳しくは、こちらの記事をご覧ください。
次の答えはどれも正しくありません。これらの方法はすべて似ているように見えますが、実際にはまったく異なることを行います。短いコメントをするのは難しいです。これらのメソッドに関する完全なドキュメントへのリンクを提供することをお勧めします:http : //docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html
上記の答えはどれも完全ではありません。レオ・セオバルドの答えは最も近い答えに見えますが。
基本的なポイントは、Hibernateがエンティティの状態をどのように処理するか、および状態が変化した場合にエンティティがそれらをどのように処理するかです。すべてがフラッシュとコミットに関しても見られる必要があり、誰もが完全に無視しているようです。
ハイバネートの保存方法は絶対に使用しないでください。それも冬眠に存在することを忘れてください!
持続する
誰もが説明したように、Persistは基本的にエンティティを「一時的な」状態から「管理された」状態に移行します。この時点で、slushまたはcommitによって挿入ステートメントを作成できます。ただし、エンティティは引き続き「管理」状態のままです。フラッシュしても変わりません。
この時点で再び「持続」しても、変化はありません。そして、永続化されたエンティティを永続化しようとすると、これ以上の節約はありません。
エンティティを立ち退かせようとするときに、楽しみが始まります。
エビクトはHibernateの特別な機能であり、エンティティを「管理」から「分離」に移行します。分離されたエンティティの永続性を呼び出すことはできません。その場合、Hibernateは例外を発生させ、トランザクション全体がコミット時にロールバックされます。
マージと更新
これらは、さまざまな方法で処理されるときにさまざまなことを行う2つの興味深い関数です。どちらも、エンティティを「切り離された」状態から「管理された」状態に移行しようとしています。しかし、それは別の方法で行います。
デタッチドが一種の「オフライン」状態を意味するという事実を理解してください。管理とは「オンライン」状態を意味します。
以下のコードを確認してください。
Session ses1 = sessionFactory.openSession();
Transaction tx1 = ses1.beginTransaction();
HibEntity entity = getHibEntity();
ses1.persist(entity);
ses1.evict(entity);
ses1.merge(entity);
ses1.delete(entity);
tx1.commit();
あなたがこれをするとき?どうなると思いますか?これが例外を発生させるとあなたが言ったなら、あなたは正しいです。マージは、切り離された状態であるエンティティオブジェクトに対して機能したため、これにより例外が発生します。ただし、オブジェクトの状態は変更されません。
背後では、mergeは選択クエリを発生させ、基本的にアタッチされた状態のエンティティのコピーを返します。以下のコードを確認してください。
Session ses1 = sessionFactory.openSession();
Transaction tx1 = ses1.beginTransaction();
HibEntity entity = getHibEntity();
ses1.persist(entity);
ses1.evict(entity);
HibEntity copied = (HibEntity)ses1.merge(entity);
ses1.delete(copied);
tx1.commit();
上記のサンプルが機能するのは、マージによって新しいエンティティが永続化された状態のコンテキストに取り込まれたためです。
Updateを適用すると、実際には更新がマージのようなエンティティのコピーをもたらさないため、同じようにうまくいきます。
Session ses1 = sessionFactory.openSession();
Transaction tx1 = ses1.beginTransaction();
HibEntity entity = getHibEntity();
ses1.persist(entity);
ses1.evict(entity);
ses1.update(entity);
ses1.delete(entity);
tx1.commit();
同時にデバッグトレースでは、Updateがselect like mergeのSQLクエリを発生させていないことがわかります。
削除する
上記の例では、削除について説明せずに削除を使用しました。削除は基本的にエンティティを管理状態から「削除」状態に移行します。フラッシュまたはコミットすると、保存する削除コマンドが発行されます。
ただし、persistメソッドを使用して、エンティティを「削除」状態から「管理」状態に戻すことができます。
上記の説明で疑問が明らかになったといいのですが。