Hibernateには、オブジェクトを取得してデータベースに格納するメソッドがいくつかあります。それらの違いは何ですか、どれを使用するか、何を使用するかを知っているインテリジェントな方法が1つだけではないのはなぜですか?
これまでに特定した方法は次のとおりです。
save()
update()
saveOrUpdate()
saveOrUpdateCopy()
merge()
persist()
これがメソッドの理解です。主にこれらは API に基づいていますが、実際にはこれらのすべてを使用しているわけではありません。
saveOrUpdateいくつかのチェックに応じて、保存または更新を呼び出します。例えば。識別子が存在しない場合、saveが呼び出されます。それ以外の場合、更新が呼び出されます。
saveエンティティを永続化します。存在しない場合は識別子を割り当てます。もしそうなら、それは本質的に更新を行っています。生成されたエンティティのIDを返します。
update既存の識別子を使用してエンティティを永続化しようとします。識別子が存在しない場合、例外がスローされると思います。
saveOrUpdateCopyこれは非推奨であり、使用しないでください。代わりに...
merge今、ここから私の知識が揺らぎ始めます。ここで重要なのは、一時的なエンティティ、分離されたエンティティ、永続的なエンティティの違いです。オブジェクトの状態の詳細については、 こちらをご覧ください 。保存と更新では、永続オブジェクトを扱います。これらはセッションにリンクされているため、Hibernateは何が変更されたかを認識します。しかし、一時オブジェクトがある場合、セッションは関係しません。これらの場合、更新にはマージを使用し、保存には永続化する必要があります。
persist前述のように、これは一時オブジェクトで使用されます。生成された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() ║
║ ║ ║ ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
永続化と保存の微妙な違いについては、 Hibernate Forum をご覧ください。違いは、INSERTステートメントが最終的に実行される時間であるように見えます。 saveは識別子を返すため、トランザクションの状態に関係なくINSERTステートメントを即座に実行する必要があります(一般に悪いことです)。 Persistは、識別子を割り当てるためだけに、現在実行中のトランザクション以外のステートメントを実行しません。 Save/Persistはtransientインスタンスで動作します。つまり、まだ識別子が割り当てられていないインスタンスはDBに保存されません。
UpdateおよびMerge両方がで動作しますインスタンス、つまり、DBに対応するエントリがあるが、現在セッションにアタッチされていない(またはセッションによって管理されていない)インスタンス。それらの違いは、関数に渡されるインスタンスに何が起こるかです。 updateは、インスタンスを再接続しようとします。つまり、現在セッションに接続されている永続エンティティの他のインスタンスが存在しない可能性があり、そうでない場合は例外がスローされます。 mergeただし、セッション内の永続インスタンスにすべての値をコピーします(現在ロードされていない場合はロードされます)。入力オブジェクトは変更されません。 mergeはupdateより一般的ですが、より多くのリソースを使用する場合があります。
このリンクは良い方法で説明しています:
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
私たちは皆、これらの問題にまれにしか遭遇しないので、それらをもう一度見ると、これを解決したことがわかりますが、どのように覚えているかはわかりません。
HibernateでSession.saveOrUpdate()を使用するときにスローされるNonUniqueObjectExceptionは私のものの1つです。複雑なアプリケーションに新しい機能を追加します。私のユニットテストはすべてうまくいきます。次に、UIをテストしてオブジェクトを保存しようとすると、「同じ識別子の値を持つ別のオブジェクトが既にセッションに関連付けられています」というメッセージで例外が発生し始めます。Java Persistence with 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));
session2.update(item); // Throws NonUniqueObjectException
tx2.commit();
session2.close();
この例外の原因を理解するには、デタッチされたオブジェクトと、デタッチされたオブジェクトでsaveOrUpdate()(または単にupdate())を呼び出したときに何が起こるかを理解することが重要です。
個々のHibernate Sessionを閉じると、作業している永続オブジェクトは切り離されます。つまり、データはアプリケーションのメモリに残っていますが、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();
マージでは、インスタンスの新しく更新されたバージョンへの参照が返されることに注意することが重要です。セッションにアイテムを再添付するものではありません。インスタンスの等価性(item == item3)をテストすると、この場合falseが返されることがわかります。この時点から、おそらくitem3を使用したいと思うでしょう。
また、Java Persistence API(JPA)には、オブジェクトの分離および再接続の概念がなく、EntityManager.persist()およびEntityManager.merge()を使用することに注意することも重要です。
一般に、Hibernateを使用する場合、saveOrUpdate()は通常、私のニーズに十分であることがわかりました。通常、同じタイプのオブジェクトへの参照を持つオブジェクトがある場合にのみ、マージを使用する必要があります。ごく最近、例外の原因は、参照が再帰的ではないことを検証するコードにありました。検証の一部として同じオブジェクトをセッションにロードしていたため、エラーが発生しました。
この問題はどこで発生しましたか?マージはうまくいきましたか、または別のソリューションが必要でしたか?常にマージを使用しますか、それとも特定の場合に必要な場合にのみ使用しますか?
すべてのhibernate saveメソッドの違いを示す良い例を見つけました:
http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example
簡単に言えば、上記のリンクによると:
save()
persist()
saveOrUpdate()
トランザクションの有無にかかわらず使用できます。save()と同様に、トランザクションなしで使用した場合、マップされたエンティティは保存されません。セッションをフラッシュします。
提供されたデータに基づいて、クエリを挿入または更新します。データベースにデータが存在する場合、更新クエリが実行されます。
update()
merge()
また、これらすべての実用的な例については、上記のリンクを参照してください。これらのすべての異なる方法の例を示しています。
実際、hibernate save()
メソッドとpersist()
メソッドの違いは、使用しているジェネレータークラスによって異なります。
ジェネレータークラスが割り当てられている場合、save()
メソッドとpersist(
)メソッドの間に違いはありません。ジェネレーターは「割り当てられた」ことを意味するため、プログラマーとしてデータベースに保存する主キー値を指定する必要があります[このジェネレーターの概念を知っていることを願っています] hibernate it selfは、プライマリキーid値をデータベースの右に割り当てます[割り当てられたジェネレーター以外、hibernateはプライマリキーid値を保持するためにのみ使用されるため、この場合、save()
またはpersist()
メソッドは、データベースにレコードを通常挿入しますが、save()
メソッドは、hibernateによって生成された主キーID値を返すことができ、
long s = session.save(k);
これと同じ場合、persist()
はクライアントに値を返しません。
デタッチされたオブジェクトで更新を呼び出すと、オブジェクトを変更したかどうかに関係なく、データベースで常に更新が行われることに注意してください。希望どおりでない場合は、LockMode.NoneでSession.lock()を使用する必要があります。
Updateは、オブジェクトが現在のセッションの範囲外で変更された場合にのみ呼び出す必要があります(デタッチモードの場合)。
この記事 で説明したように、ほとんどの場合はJPAメソッドを、バッチ処理タスクにはupdate
を好むはずです。
JPAまたはHibernateエンティティは、次の4つの状態のいずれかになります。
ある状態から別の状態への遷移は、EntityManagerまたはSessionメソッドを介して行われます。
たとえば、JPA EntityManager
は、次のエンティティ状態遷移メソッドを提供します。
Hibernate Session
はすべてのJPA EntityManager
メソッドを実装し、save
、saveOrUpdate
、update
などの追加のエンティティ状態遷移メソッドを提供します。
エンティティの状態をTransient(New)からManaged(Persisted)に変更するには、JPA persist
によって提供されるEntityManager
メソッドを使用できます。これは、Hibernate Session
によっても継承されます。
persist
メソッドは、PersistEvent
Hibernateイベントリスナーによって処理されるDefaultPersistEventListener
をトリガーします。
したがって、次のテストケースを実行する場合:
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
がFirst-Level Cacheとして知られている理由です。
persist
を呼び出すと、エンティティは現在実行中の永続コンテキストにのみ接続され、flush
が呼び出されるまでINSERTを延期できます。
唯一の例外は IDENTITYジェネレーター です。これは、エンティティ識別子を取得できる唯一の方法であるため、すぐにINSERTをトリガーします。このため、HibernateはIDENTITYジェネレーターを使用してエンティティの挿入をバッチ処理できません。このトピックの詳細については、 この記事 をご覧ください。
Hibernate固有のsave
メソッドはJPAより前のバージョンであり、Hibernateプロジェクトの開始以来利用可能になっています。
save
メソッドは、SaveOrUpdateEvent
Hibernateイベントリスナーによって処理されるDefaultSaveOrUpdateEventListener
をトリガーします。したがって、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
Hibernateイベントリスナーによって処理されるDefaultSaveOrUpdateEventListener
をトリガーします。したがって、update
メソッドは、save
およびsaveOrUpdate
メソッドと同等です。
update
メソッドがどのように機能するかを確認するには、1つのトランザクションでBook
エンティティを保持し、エンティティが切り離された状態でそれを変更し、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
Hibernateアノテーションを使用して、loaded state
をフェッチしたSELECT
ステートメントをトリガーし、ダーティチェックメカニズムで使用します。
そのため、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
今回は、Hibernateのダーティチェックメカニズムがエンティティが変更されていないことを検出したため、UPDATE
が実行されないことに注意してください。
Hibernate固有のsaveOrUpdate
メソッドは、単にsave
およびupdate
のエイリアスです。
saveOrUpdate
メソッドは、SaveOrUpdateEvent
Hibernateイベントリスナーによって処理されるDefaultSaveOrUpdateEventListener
をトリガーします。したがって、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
で発生する可能性のある問題の1つは、永続コンテキストに次の例と同じ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
にBook
に渡す識別子と同じ識別子を持つupdate
エンティティが既に含まれており、永続コンテキストが同じエンティティの2つの表現を保持できないためです。
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
を回避するには、JPA merge
によって提供され、Hibernate EntityManager
によって継承されるSession
メソッドを使用する必要があります。
この記事 で説明したように、永続コンテキストでエンティティ参照が見つからない場合、merge
はデータベースから新しいエンティティスナップショットを取得し、merge
メソッドに渡された分離されたエンティティの状態をコピーします。
merge
メソッドは、MergeEvent
Hibernateイベントリスナーによって処理されるDefaultMergeEventListener
をトリガーします。
merge
メソッドがどのように機能するかを確認するには、1つのトランザクションでBook
エンティティを永続化し、エンティティが切り離された状態にある間にそれを変更し、サブシーケンス永続コンテキストで切り離されたエンティティを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
メソッドに渡したデタッチされたものとは異なることに注意してください。
現在、デタッチされたエンティティの状態をコピーするときにJPA merge
を使用することをお勧めしますが、バッチ処理タスクを実行するときに余分な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は基本的にエンティティを「Transient」状態から「Managed」状態に移行します。この時点で、スラッシュまたはコミットによりinsertステートメントを作成できます。ただし、エンティティは「管理」状態のままです。フラッシュしてもそれは変わりません。
この時点で、再度「永続化」しても変更はありません。そして、永続化されたエンティティを永続化しようとすると、それ以上の保存はありません。
楽しみは、エンティティを追い出そうとしたときに始まります。
エビクトはHibernateの特別な機能であり、エンティティを「管理対象」から「分離」に移行します。分離されたエンティティで永続化を呼び出すことはできません。それを行うと、Hibernateは例外を発生させ、トランザクション全体がコミット時にロールバックされます。
マージと更新
これらは、異なる方法で処理されたときに異なることを行う2つの興味深い関数です。どちらも、エンティティを「切り離された」状態から「管理された」状態に移行しようとしています。しかし、異なる方法でそれを行います。
Detachedは一種の「オフライン」状態を意味するという事実を理解してください。管理対象は「オンライン」状態を意味します。
以下のコードを確認してください。
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();
これをするとき?何が起こると思いますか?これが例外を発生させると言った場合、あなたは正しいです。これは、マージがエンティティオブジェクトに対して機能しているため、例外が発生します。これは、切り離された状態です。ただし、オブジェクトの状態は変更されません。
舞台裏では、マージは選択クエリを発生させ、基本的には接続状態のエンティティのコピーを返します。以下のコードを確認してください。
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();
上記のサンプルは、マージによって新しいエンティティが永続化された状態のコンテキストに取り込まれたため機能します。
更新を適用しても、実際にはマージのようなエンティティのコピーは取得されないため、同じように機能します。
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のSQLクエリを発生させていないことがわかります。
削除
上記の例では、削除について説明せずに削除を使用しました。削除は基本的に、エンティティを管理状態から「削除」状態に移行します。また、フラッシュまたはコミットされると、保存する削除コマンドが発行されます。
ただし、永続メソッドを使用して、エンティティを「削除」状態から「管理」状態に戻すことができます。
上記の説明が疑問を明確にしたことを願っています。