簡體   English   中英

Hibernate 中不同的保存方法有什么區別?

[英]What are the differences between the different saving methods in Hibernate?

Hibernate 有一些方法,它們以一種或另一種方式獲取您的對象並將其放入數據庫。 它們之間有什么區別,何時使用哪個,為什么沒有一種智能方法知道何時使用什么?

到目前為止,我確定的方法是:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()

以上是我對方法的理解。 盡管我在實踐中並沒有使用所有這些,但主要是基於API

saveOrUpdate根據某些檢查調用 save 或 update。 例如,如果不存在標識符,則調用 save。 否則調用更新。

save持久化一個實體。 如果不存在,將分配一個標識符。 如果有,它本質上是在進行更新。 返回生成的實體 ID。

更新嘗試使用現有標識符持久化實體。 如果不存在標識符,我相信會拋出異常。

saveOrUpdateCopy這已被棄用,不應再使用。 反而有...

合並現在這是我的知識開始動搖的地方。 這里重要的是瞬態、分離和持久實體之間的區別。 有關對象狀態的更多信息, 請查看此處 使用保存和更新,您正在處理持久對象。 它們與會話相關聯,因此 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()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
  • 請參閱Hibernate 論壇以獲取有關 persist 和 save 之間細微差別的說明。 看起來區別在於 INSERT 語句最終執行的時間。 由於save確實返回標識符,因此無論事務的狀態如何(這通常是一件壞事)都必須立即執行 INSERT 語句。 Persist不會在當前運行的事務之外執行任何語句,只是為了分配標識符。 Save/Persist 都適用於瞬態實例,即尚未分配標識符的實例,因此不會保存在數據庫中。

  • 更新合並都適用於分離的實例,即在數據庫中有相應條目但當前未附加到(或由其管理)會話的實例。 它們之間的區別在於傳遞給函數的實例會發生什么。 update嘗試重新附加實例,這意味着現在不能有其他持久實體的實例附加到會話,否則會拋出異常。 但是, merge只是將所有值復制到 Session 中的持久實例(如果當前未加載,則將加載該實例)。 輸入對象沒有改變。 因此mergeupdate更通用,但可能會使用更多資源。

大多數時候您應該更喜歡 JPA 方法,以及批處理任務的update

JPA 或 Hibernate 實體可以處於以下四種狀態之一:

  • 瞬態(新)
  • 托管(持續)
  • 獨立的
  • 移除(刪除)

從一種狀態到另一種狀態的轉換是通過 EntityManager 或 Session 方法完成的。

例如,JPA EntityManager提供以下實體狀態轉換方法。

JPA 實體狀態轉換

Hibernate Session實現了所有 JPA EntityManager方法並提供了一些額外的實體狀態轉換方法,如savesaveOrUpdateupdate

Hibernate 實體狀態轉換

堅持

要將實體的狀態從 Transient (New) 更改為 Managed (Persisted),我們可以使用 JPA EntityManager提供的persist方法,該方法也由 Hibernate Session繼承。

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
)

請注意,在將Book實體附加到當前持久性上下文之前分配了id 這是必需的,因為托管實體存儲在Map結構中,其中鍵由實體類型及其標識符構成,值是實體引用。 這就是 JPA EntityManager和 Hibernate Session被稱為一級緩存的原因。

調用persist ,實體僅附加到當前運行的 Persistence Context,並且可以推遲 INSERT 直到調用flush

唯一的例外是IDENTITY ,它立即觸發 INSERT,因為這是獲取實體標識符的唯一方法。 因此,Hibernate 無法使用IDENTITY生成器批量插入實體。

節省

特定於 Hibernate 的save方法早於 JPA,並且它自 Hibernate 項目開始就可用。

save方法觸發由DefaultSaveOrUpdateEventListener Hibernate 事件偵聽器處理的SaveOrUpdateEvent 因此, save方法等效於updatesaveOrUpdate方法。

要查看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方法觸發由DefaultSaveOrUpdateEventListener Hibernate 事件偵聽器處理的SaveOrUpdateEvent 因此, update方法等效於savesaveOrUpdate方法。

要了解update方法的工作原理,請考慮以下示例,該示例將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是在 Persistence Context 刷新期間執行的,就在提交之前,這就是為什么首先記錄Updating the Book entity消息的原因。

使用@SelectBeforeUpdate避免不必要的更新

現在,即使實體在分離狀態下未更改,也將始終執行 UPDATE。 為了防止這種情況,您可以使用@SelectBeforeUpdate Hibernate 注釋,它會觸發一個SELECT語句,該語句獲取loaded state ,然后由臟檢查機制使用。

因此,如果我們使用@SelectBeforeUpdate注釋來注釋Book實體:

@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方法只是saveupdate的別名。

saveOrUpdate方法觸發由DefaultSaveOrUpdateEventListener Hibernate 事件偵聽器處理的SaveOrUpdateEvent 因此, update方法等效於savesaveOrUpdate方法。

現在,當您想要持久化實體或強制執行UPDATE時,您可以使用saveOrUpdate ,如下例所示。

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

saveupdatesaveOrUpdate可能出現的一個問題是,持久化上下文是否已經包含與以下示例具有相同 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因為第二個EntityManager已經包含一個Book實體,其標識符與我們傳遞給update標識符相同,並且 Persistence Context 不能保存同一實體的兩個表示。

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 EntityManager提供的並由 Hibernate Session繼承的merge方法。

如果在 Persistence Context 中沒有找到實體引用, merge從數據庫中獲取一個新的實體快照,並復制傳遞給merge方法的分離實體的狀態。

merge方法會觸發一個MergeEvent ,它由DefaultMergeEventListener Hibernate 事件偵聽器處理。

要了解merge方法的工作原理,請考慮以下示例,該示例在一個事務中持久化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方法僅對批處理任務有用。 savesaveOrUpdate只是update別名,您可能根本不應該使用它們。

即使實體已經被管理,一些開發人員也會調用save ,但這是一個錯誤並觸發一個冗余事件,因為對於被管理的實體,更新是在 Persistence 上下文刷新時間自動處理的。

這個鏈接很好地解釋了:

http://www.stevider.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/

我們都有那些我們很少遇到的問題,以至於當我們再次看到它們時,我們知道我們已經解決了這個問題,但不記得是如何解決的。

在 Hibernate 中使用 Session.saveOrUpdate() 時拋出的 NonUniqueObjectException 是我的一種。 我將向復雜的應用程序添加新功能。 我所有的單元測試工作正常。 然后在測試 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();

請務必注意,merge 返回對實例新更新版本的引用。 它不會將項目重新附加到會話。 如果您測試實例相等性 (item == item3),您會發現在這種情況下它返回 false。 從現在開始,您可能希望使用 item3。

同樣重要的是要注意 Java Persistence API (JPA) 沒有分離和重新附加對象的概念,而是使用 EntityManager.persist() 和 EntityManager.merge()。

我發現一般來說,在使用 Hibernate 時,saveOrUpdate() 通常足以滿足我的需要。 我通常只在對象可以引用相同類型的對象時才需要使用合並。 最近,異常的原因在於驗證引用不是遞歸的代碼中。 作為驗證的一部分,我將同一個對象加載到我的會話中,從而導致了錯誤。

你在哪里遇到過這個問題? 合並對您有用還是您需要其他解決方案? 您更喜歡始終使用合並,還是更喜歡僅在特定情況下需要時使用它

實際上,hibernate save()persist()方法之間的區別取決於我們使用的生成器類。

如果我們的生成器類被賦值,那么save()persist( ) 方法之間沒有區別。 因為generator 'assigned' 的意思是,作為程序員,我們需要給主鍵值以保存在數據庫中的權利[希望你知道這個generators概念] 如果不是分配的generator class,假設我們的generator class name is Increment 意味着休眠它自己會將主鍵id值分配到數據庫中[除了分配的生成器,休眠僅用於記住主鍵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

簡而言之,根據上面的鏈接:

節省()

  • 我們可以在事務之外調用這個方法。 如果我們在沒有事務的情況下使用它並且我們在實體之間進行級聯,那么除非我們刷新會話,否則只會保存主要實體。
  • 因此,如果有從主對象映射的其他對象,它們會在提交事務或刷新會話時保存。

堅持()

  • 它類似於在事務中使用 save() ,因此它是安全的並且可以處理任何級聯對象。

保存或更新()

  • 可以在有或沒有事務的情況下使用,就像 save() 一樣,如果它在沒有事務的情況下使用,映射的實體不會被保存;除非我們刷新會話。

  • 根據提供的數據插入或更新查詢的結果。 如果數據存在於數據庫中,則執行更新查詢。

更新()

  • 當我們知道我們只更新實體信息時,應該使用 Hibernate update。 此操作將實體對象添加到持久上下文,並在提交事務時跟蹤和保存進一步的更改。
  • 因此,即使在調用 update 之后,如果我們在實體中設置任何值,它們也會在事務提交時更新。

合並()

  • Hibernate 合並可用於更新現有值,但是此方法從傳遞的實體對象創建副本並返回它。 返回的對象是持久上下文的一部分,並跟蹤任何更改,不跟蹤傳遞的對象。 這是 merge() 與所有其他方法的主要區別。

對於所有這些的實際示例,請參閱我上面提到的鏈接,它顯示了所有這些不同方法的示例。

請注意,如果您對分離的對象調用更新,則無論您是否更改了對象,數據庫中都將進行更新。 如果這不是你想要的,你應該使用 Session.lock() 和 LockMode.None。

僅當對象在當前會話范圍之外(處於分離模式時)發生更改時,才應調用 update。

以下答案都不對。 所有這些方法看起來都一樣,但實際上做的事情完全不同。 很難給出簡短的評論。 最好提供有關這些方法的完整文檔的鏈接: http : //docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

以上答案都不完整。 盡管 Leo Theobald 的回答看起來最接近。

基本點是 hibernate 如何處理實體的狀態以及當狀態發生變化時它如何處理它們。 關於刷新和提交的一切都必須被看到,每個人似乎都完全忽略了這一點。

切勿使用 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();

上述示例之所以有效,是因為合並已將一個新實體帶入處於持久狀態的上下文中。

當與更新一起應用時,同樣的工作正常,因為更新實際上並沒有帶來像合並這樣的實體副本。

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();

同時在調試跟蹤中我們可以看到更新沒有像合並一樣引發選擇的 SQL 查詢。

刪除

在上面的例子中,我使用了 delete 而沒有談到 delete。 刪除基本上會將實體從托管狀態轉換為“已刪除”狀態。 並且在刷新或提交時會發出刪除命令來存儲。

但是,可以使用persist 方法將實體從“已刪除”狀態帶回“托管”狀態。

希望以上的解​​釋能澄清大家的疑惑。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM