簡體   English   中英

JPA 和 Hibernate 中的 persist() 和 merge() 有什么區別?

[英]What is the difference between persist() and merge() in JPA and Hibernate?

Hibernate 中的persist() 和merge() 有什么區別?

persist()可以創建一個 UPDATE & INSERT 查詢,例如:

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
A a=new A();
session.persist(a);
a.setName("Mario");
session.flush();

在這種情況下,查詢將像這樣生成:

Hibernate: insert into A (NAME, ID) values (?, ?)
Hibernate: update A set NAME=? where ID=?

所以persist()方法可以生成一個插入和一個更新。

現在使用merge()

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
Singer singer = new Singer();
singer.setName("Luciano Pavarotti");
session.merge(singer);
session.flush();

這是我在數據庫中看到的:

SINGER_ID   SINGER_NAME
1           Ricky Martin
2           Madonna
3           Elvis Presley
4           Luciano Pavarotti

現在使用merge()更新記錄

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
Singer singer = new Singer();
singer.setId(2);
singer.setName("Luciano Pavarotti");
session.merge(singer);
session.flush();

這是我在數據庫中看到的:

SINGER_ID   SINGER_NAME
1           Ricky Martin
2           Luciano Pavarotti
3           Elvis Presley

JPA 規范包含對這些操作語義的非常精確的描述,比 javadoc 中的要好:

應用於實體 X 的持久操作的語義如下:

  • 如果 X 是一個新實體,它將成為托管。 實體 X 將在事務提交時或之前或作為刷新操作的結果輸入到數據庫中。

  • 如果 X 是預先存在的受管實體,則持久操作將忽略它。 但是,如果從 X 到這些其他實體的關系使用cascade=PERSISTcascade=ALL注釋元素值注釋或使用等效的 XML 描述符元素指定,則持久操作級聯到由 X 引用的實體。

  • 如果 X 是已刪除的實體,則它變為托管的。

  • 如果X是一個分離的目的, EntityExistsException當persist操作被調用時,或者可能拋出EntityExistsException或另一個PersistenceException可以在沖洗被拋出或提交時間。

  • 對於由來自 X 的關系引用的所有實體 Y,如果與 Y 的關系已使用級聯元素值cascade=PERSISTcascade=ALL進行注釋,則對 Y 應用持久操作。


應用於實體 X 的合並操作的語義如下:

  • 如果 X 是分離的實體,則 X 的狀態被復制到具有相同身份的預先存在的受管實體實例 X' 上,或者創建 X 的新受管副本 X'。

  • 如果 X 是新的實體實例,則創建新的受管實體實例 X',並將 X 的狀態復制到新的受管實體實例 X'。

  • 如果 X 是已刪除的實體實例,則合並操作將拋出IllegalArgumentException (否則事務提交將失敗)。

  • 如果 X 是受管實體,則合並操作將忽略它,但是,如果這些關系已使用級聯元素值cascade=MERGEcascade=ALL注釋,則合並操作級聯到由來自 X 的關系引用的實體。

  • 對於由來自 X 的關系引用的所有實體 Y 具有級聯元素值cascade=MERGEcascade=ALL ,Y 被遞歸合並為 Y'。 對於 X 引用的所有此類 Y,X' 設置為引用 Y'。 (請注意,如果 X 是被管理的,那么 X 與 X' 是同一個對象。)

  • 如果 X 是合並到 X' 的實體,並引用另一個實體 Y,其中未指定cascade=MERGEcascade=ALL ,則從 X' 導航相同關聯會產生對托管對象 Y' 的引用與 Y 相同的持久身份。

這是來自JPA 以一種非常簡單的方式:

  • persist(entity)應該與全新的實體一起使用,將它們添加到 DB(如果 DB 中已經存在實體,則會拋出 EntityExistsException)。

  • 應該使用merge(entity) ,如果實體被分離並被更改,則將實體放回持久性上下文。

Persist 應該只在新實體上調用,而merge意味着重新附加分離的實體。

如果您使用指定的生成器,使用merge而不是persist可能會導致冗余的 SQL 語句。

此外,為托管實體調用合並也是一個錯誤,因為托管實體由 Hibernate 自動管理,並且它們的狀態在刷新持久性上下文時通過臟檢查機制與數據庫記錄同步。

最重要的區別是:

  • persist方法的情況下,如果要在持久化上下文中管理的實體已經存在於持久化上下文中,則忽略新的實體。 (什么都沒有發生)

  • 但是在merge方法的情況下,已經在持久化上下文中管理的實體將被新實體(更新)替換,並且這個更新實體的副本將返回。 (從現在開始,如果您想在持久性上下文中反映您的更改,則應對此返回的實體進行任何更改)

暫無
暫無

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

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