2010-06-15 56 views
3

讓我們看看一個簡單的狗和貓朋友的例子。這並不罕見。它還有比我的商業案例更有趣的好處。瞭解休眠saveOrUpdate和持久生命週期

我們需要一個名爲「saveFriends」的函數,它需要一個狗的名字和一個貓的名字。我們將保存狗和貓。爲了這個例子的工作,貓將會有一個參考回到狗。我知道這不是一個理想的例子,但它很可愛,適用於我們的目的。

FriendService.java

public int saveFriends(String dogName, String catName) { 
    Dog fido = new Dog(); 
    Cat felix = new Cat(); 

    fido.name = dogName; 
    fido = animalDao.saveDog(fido); 

    felix.name = catName; 
    [ex.A]felix.friend = fido; 
    [ex.B]felix.friend = animalDao.getDogByName(dogName); 
    animalDao.saveCat(felix); 
} 

AnimalDao.java(延伸的HibernateDaoSupport)現在

public Dog saveDog(Dog dog) { 
    getHibernateTemplate().saveOrUpdate(dog); 
    return dog 
} 

public Cat saveCat(Cat cat) { 
    getHibernateTemplate().saveOrUpdate(cat); 
    return cat; 
} 

public Dog getDogByName(String name) { 
    return (Dog) getHibernateTemplate().find("from Dog where name=?", name).get(0); 
} 

,假設一分鐘,我想爲使用實施例A或例子B保存我的朋友。一個比另一個更好用嗎?

此外,不會舉例B讓你臭名昭着的「非空屬性引用空值或瞬態值」錯誤?我只是在這裏猜測,但我會認爲這是因爲狗仍然在會議中。

我會理解這些例子是否都不起作用,但請解釋原因。

+0

這些實體的標識符是什麼? – mdma 2010-06-15 20:58:08

+0

@mdma我想我們可以說他們有通常的「id」字段作爲標識符。 – Stephano 2010-06-15 22:27:45

+0

@Sephano - 謝謝 - 我不得不問 - 可能是因爲名字被用作id--目前還不清楚saveFriends是否正在創建新的瞬變並持續它們,或者可能更新現有的持久實體(來自名稱。 ) – mdma 2010-06-15 22:38:43

回答

4

現在,假設我想用例A或例B保存我的朋友一分鐘。一個比另一個更好用嗎?

兩個例子就可以了(在例子B,Hibernate會flush the session before query executions所以它會插入之前選擇狗),但我不認爲做一個額外的選擇(例如B)的時候你已經有狗實例。我會舉個例子A.

此外,不會舉例B讓你臭名昭着的「非空屬性引用空值或瞬態值」錯誤?

否(見上文)。在例子B中,狗不再是短暫的。在例A中,插入將按照正確的順序完成。

我只是在這裏猜測,但我會認爲這是因爲狗仍然在會議中。

第一級緩存(會話)用於通過id查找,在這裏不是這種情況。

+0

+1非常好的答案。顯然,我需要刷新緩存的級別。 – Stephano 2010-06-15 22:26:40

+0

你是對的,第一級緩存僅用於by-id查找,但在'felix.friend = animalDao.getDogByName(dogName)'後面,如果我沒有記錯,Hibernate保證'felix.friend == fido', RT? – 2010-06-15 23:04:06

+0

(假設'name'是'Dog'的一個獨特屬性) – 2010-06-15 23:05:24

2

從文檔在hibernate

saveOrUpdate()方法執行以下操作:

如果對象是已持續在這個會議上,什麼也不做

如果與會話相關的另一個對象有相同的標識符,拋出異常

如果對象沒有標識符屬性,則保存()它

如果對象的標識符具有分配給一個新實例化的對象的值,保存()它

如果對象是由一個或版本化,並且版本屬性值是分配給一個新實例化的對象相同的值,保存()它

否則update()這個對象

明智的性能我想說分配參照對象,菲多點會更快,因爲你沒有打開到數據庫的連接。

+0

+1往返的好處。根據您以前的建議,我改變了標題。我想我也很好奇Ex.2是否可以工作,或者自從該對象還在會話中之後會發生衝突? – Stephano 2010-06-15 20:14:58

+0

我相信會執行一次保存,因爲既然「如果對象已經在這個會話中持久,什麼也不做」,或者「如果與會話相關的另一個對象具有相同的標識符,拋出異常」在方法時爲真調用。因此,這個對象將被保存。這當然可能是不正確的,但看着這個小片段,我相信這是正確的。 – Woot4Moo 2010-06-15 20:32:19

2

兩者都能正常工作,但效率不高。在B之下,因爲它執行查詢,它不僅具有查詢本身的開銷,而且強制hibernate清除對數據庫的更改 - 在事務被提交之前可能保留在內存中的更改,並與許多其他變化。

與db的連接通常會承受相當高的延遲,所以使用批處理一次髮送很多更改,從而減少每個語句的延遲。將變更集分解爲許多小的變更會導致每個語句的開銷比一組更大的變更更高。所以,最好儘可能一起提交更改。

+0

關於「太早沖洗」的額外費用的好處。 +1 – 2010-06-16 07:36:26