hibernate merge與update區別

今天做了個測試,寫了個測試用例來看看merge與update時控制檯打印出來的日誌有什麼不一樣。實體bean很簡單,就id和name兩個字段,接下來分別給出以下幾種測試情形的控制檯日誌內容:


[b]1. 數據庫記錄已存在,更改person的name爲一個新的name。 [/b]

[color=brown]merge方法打印出的日誌如下: [/color]
Hibernate: select person0_.id as id0_0_, person0_.name as name0_0_ from
person person0_ where person0_.id=?
Hibernate: update person set name=?
where id=?


[color=brown]update方法打印出的日誌如下: [/color]
Hibernate: update person set name=?
where id=?


[b]2. 數據庫記錄已存在,更改person的name和數據庫裏對應id記錄的name一樣的值。 [/b]

[color=brown]merge方法打印出的日誌如下: [/color]
Hibernate: select person0_.id as id0_0_,
person0_.name as name0_0_ from person person0_ where person0_.id=?
此處相對於第一種情形少了update的動作


[color=brown]update方法打印出的日誌如下: [/color]
Hibernate: update person set name=? where id=?


[b]3. 數據庫記錄不存在。也就是你傳的實體bean的ID在數據庫沒有對應的記錄。 [/b]

[color=brown]merge方法打印出的日誌如下: [/color]
Hibernate: select person0_.id as id0_0_, person0_.name as name0_0_
from person person0_ where person0_.id=?
Hibernate: insert into person (name) values (?)

如果沒有對應的記錄,merge會把該記錄當作新的記錄來插入。
[color=olive]
此處我很疑惑,因爲我傳得person實體對象裏寫明瞭id值的,它爲什麼還會做插入的動作呢?(如果使用不好,則會在更新時,不會更新而是新增一行記錄!!!)
在做更新操作時,在merge之前先要持久化一下?
[/color]


[color=brown]update方法打印出的日誌如下: [/color]
Hibernate: update person set name=? where id=?

2009-11-22 20:59:55,359 ERROR [org.hibernate.jdbc.AbstractBatcher] -
Exception executing batch:
org.hibernate.StaleStateException: Batch update
returned unexpected row count from update [0]; actual row count: 0; expected: 1


[b]以下的內容摘抄自網上: [/b]

當我們使用update的時候,執行完成後,我們提供的對象A的狀態變成持久化狀態。

當我們使用merge的時候,執行完成後,我們提供的對象A還是脫管狀態。hibernate或者是new了一個B(此時執行插入操作),或者檢索到一個持久對象B(此時執行更新操作),並把我們提供的對象A的所有的值拷貝到這個B,執行完成後B是持久狀態,而我們提供的A還是託管狀態。


----------------------------------

使用merge方法,如果數據庫中有該記錄,則更新該記錄,如果不存在該記錄,則進行insert操作。

使用update的話,會無條件執行update。

也就是說如果數據庫中有該記錄的話,merge和update是一樣的。
但是如果數據庫中沒有該記錄,使用merge執行insert,不會報錯,而使用update會報錯。


不同之處在於,update可以持久化類,merge不行 --- 重要

---------------------------------------

假設有個Student stu類,session.update(stu),merge也是一樣。
不同之處在於,update可以持久化類,merge不行,執行session.merge(stu)之後,stu對象如果之前不是持久化狀態,stu對象依然不會被關聯到session上。

----------------------------------------

[b]誰懂得hibernate的merge方法?[/b]

我使用merge方法。老是報could not load an entity的異常。
配置文件,一定沒有問題。
於是,我寫了個junit的單元測試。這個單元測試繼承了HibernateDaoSupport,並注入了sessionFactory,並調用
this.getHibernateTemplate.merge 方法,還是could not load an entity.

是我對merge理解有問題,還是其他什麼問題?


//單元測試如下

public class MergeTest extends HibernateDaoSupport {

@Test
public void testMerge(){

//獲取spring配置
ApplicationContext act = new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/applicationContext.xml");

//注入sesssionFactory
this.setSessionFactory((SessionFactory)act.getBean("sessionFactory"));

//創建一個模擬的DocumentCatalog 數據中已經有個 id = 1的數據
DocumentCatalog dc = new DocumentCatalog();

dc.setId(1);
dc.setName("crying!!!!!");

//我認爲,這時候,數據庫中的 id = 1的數據,會被update,但是,發生could not load an entity錯誤。
//數據庫映射沒有錯誤,換成update就能順利更新。
this.getHibernateTemplate().merge(dc);

}
}


用update是直接把實體和數據庫同步,而是要merge方法時 merge操作的是實體的代理對象,所以我們用它時一定要把它放到事務中執行,否則會報could not load an entity異常,
意思是在:this.getHibernateTemplate().merge(dc);語句前面開啓一個事務就OK


=========================================================

理一下思路:(沒有驗證)

使用merge方法時,
如果存在一個持久化的對象,則執行 update 操作。
如果不存在一個持久化的對象,則進行插入操作。

所以,對象需要先持久化後,再進行 merge() 。這裏的持久化不是數據庫中是否有這條記錄,而是 Hibernate 中數據的狀態。如果數據庫中存在一條記錄,而沒有被 Hibernate 持久化,使用 merge() 時,仍然執行的是新增一條記錄操作。而不是更新操作。


-
引用:
http://www.cnblogs.com/hyteddy/archive/2011/05/10/2041762.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章