hibernate中的merge()方法


Hibernate提供有save()、persist()、savaOrUpdate()和merge()等方法來提供插入數據的功能。前三者理解起來較后者容易一些,而merge()方法從api中的介紹就可以看出它是最復雜的,因此要特別留意一下。

Hibernate的api中關於merge()方法的原文

merge
Object merge(Object object)
             throws HibernateException
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with  cascade="merge"
The semantics of this method are defined by JSR-220.
Parameters:
object - a detached instance with state to be copied
Returns:
an updated persistent instance
Throws:
HibernateException

從參數說明來看,merge()方法的參數應該是一個處於托管狀態的實例對象,而返回值則是一個持久化對象。但是這里的參數並不是一定要是托管狀態的對象,它還可以是瞬態和持久化的實例對象。正因如此,才使merge方法變得復雜化。

merge()方法的作用

Hibernate中有一個常見錯誤:A different object with the same identifier value was already associated with the session,即在一個session中存在兩個不同的實體卻有着相同的身份標簽(主鍵)是會報錯的,這時為了避免這種錯誤就可以使用Hibernate提供的merge()方法。

merge()方法的使用特性

1.new一個對象並設置ID時,這個對象會被當作游離態處理,在使用merge時,如果在數據庫中不能能找到這條記錄,則使用insert將數據插入;如果在數據庫中找到這條記錄,則使用update將數據更新。

2.new一個對象沒有設置ID時,這個對象會被當作瞬態處理,在使用merge時會根據實體類的主鍵生成策略保存這條數據。

3.使用merge存儲到數據庫的對象,其本身不會轉變為持久態對象。

Hibernate中三態的補充

1.瞬態:通過Java關鍵字new的實體類對象,不和Session實例關聯並且在數據庫中沒有和瞬態對象關聯的記錄,此時的對象還沒有納入Hibernate的緩存管理中。

2.持久態: 已經被保存進數據庫的實體對象,還存於Hibernate的緩存管理之中。

3.游離態(脫管態):持久態對象脫離了Hibernate的緩存管理后就會變成游離態,游離態對象與瞬態對象的最大區別在於,游離態對象在數據庫中可能存在一條與之對應的記錄,而瞬態對象則不會在數據庫中存在與之對應的記錄,簡而言之就是游離態對象比瞬態對象多了一個ID屬性。

代碼實際校驗

經實際代碼的檢驗,從merge()方法產生的效果來看,它和saveOrUpdate()方法相似,因此雖然上面提到是因為參數狀態的不同造成復雜化,但是這里我並不打算分參數的不同狀態來理解merge()方法,而是根據參數有無id或id是否已經存在來理解merge()方法。個人認為這樣更容易理解,而且從執行他們兩個方法而產生的sql語句來看是一樣的。

1.參數實例對象沒有提供id或提供的id在數據庫中不存在,這時merge將執行插入操作,產生的sql語句如下:

Hibernate: select max(uid) from user
Hibernate: insert into hibernate1.user (name, age, uid) values (?, ?, ?)

2. 參數實例對象的id在數據庫中已經存在,此時又有兩種情況。

①如果對象有改動,則執行更新操作,產生sql語句有:

Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from hibernate1.user user0_ where user0_.uid = ? 
Hibernate: update hibernate1.user set name = ?, age = ? where uid = ?

②如果對象無改動,則執行查詢操作,產生的語句有:

Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from hibernate1.user user0_ where user0_.uid = ?

而不管哪種情況,merge的返回值都是一個持久化的實例對象,雖然對於參數而言不會改變它的狀態。

總結

雖然從功能上來說,merge()方法與saveOrUpdate()方法類似,但是他們依然是有區別的。

比如有這樣一種情況:我們先通過session的get方法得到一個對象u,然后關掉session,再打開一個session並執行saveOrUpdate(u)。此時我們可以看到拋出異常:Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session,即在session緩存中不允許有兩個id相同的對象。這時若使用merge方法則不會異常,其實從merge的中文意思(合並)我們就可以理解了。

 

"匆匆忙忙,恍恍惚惚,慌慌張張。"


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM