hibernate的各種儲存方式的區別 (save/persist/merge)
原文地址:
copy下,順便自己在重新整理一下。
hibernate的儲存
hibernate對於物件的儲存提供了太多的方法,他們之間有很多不同,這裡細說一下,以便區別:
一、預備知識:
在所有之前,說明一下,對於hibernate,它的物件有三種狀態,transient、persistent、detached
下邊是常見的翻譯辦法:
transient:瞬態或者自由態
persistent:持久化狀態
detached:脫管狀態或者遊離態
脫管狀態的例項可以通過呼叫save()、persist()或者saveOrUpdate()方法進行持久化。
持久化例項可以通過呼叫 delete()變成脫管狀態。通過get()或load()方法得到的例項都是持久化狀態的。
脫管狀態的例項可以通過呼叫 update()、0saveOrUpdate()、lock()或者replicate()進行持久化。
save()和persist()將會引發SQL的INSERT,delete()會引發SQLDELETE,
而update()或merge()會引發SQLUPDATE。對持久化(persistent)例項的修改在重新整理提交的時候會被檢測到,
它也會引起SQLUPDATE。saveOrUpdate()或者replicate()會引發SQLINSERT或者UPDATE
二、save 和update區別
把這一對放在第一位的原因是因為這一對是最常用的。
save的作用是把一個新的物件儲存
update是把一個脫管狀態的物件儲存
三,update 和saveOrUpdate區別
處於持久化的物件的任何變化,不必人工呼叫update語句,hibernate自己會執行update的sql語句。
換句話說,update動作僅僅對託管物件有用。
save僅僅對瞬時物件有用。
這個是比較好理解的,顧名思義,saveOrUpdate基本上就是合成了save和update
引用hibernate reference中的一段話來解釋他們的使用場合和區別
通常下面的場景會使用update()或saveOrUpdate():
程式在第一個session中載入物件
該物件被傳遞到表現層
物件發生了一些改動
該物件被返回到業務邏輯層
程式呼叫第二個session的update()方法持久這些改動
saveOrUpdate()做下面的事:
如果物件已經在本session中持久化了,不做任何事
如果另一個與本session關聯的物件擁有相同的持久化標識(identifier),丟擲一個異常
如果物件沒有持久化標識(identifier)屬性,對其呼叫save()
如果物件的持久標識(identifier)表明其是一個新例項化的物件,對其呼叫save()
如果物件是附帶版本資訊的(通過<version>或<timestamp>) 並且版本屬性的值表明其是一個新例項化的物件,save()它。
否則update() 這個物件
四,persist和save區別
這個是最迷離的一對,表面上看起來使用哪個都行,在hibernate reference文件中也沒有明確的區分他們.
這裡給出一個明確的區分。(可以跟進src看一下,雖然實現步驟類似,但是還是有細微的差別)
---------------------------------------------------------------------------------
I found that a lot of people have the same doubt. To help to solve this issue
I'm quoting Christian Bauer:
"In case anybody finds this thread...
persist() is well defined. It makes a transient instance persistent. However,
it doesn't guarantee that the identifier value will be assigned to the persistent
instance immediately, the assignment might happen at flush time. The spec doesn't say
that, which is the problem I have with persist().
persist() also guarantees that it will not execute an INSERT statement if it is
called outside of transaction boundaries. This is useful in long-running conversations
with an extended Session/persistence context.A method like persist() is required.
save() does not guarantee the same, it returns an identifier, and if an INSERT
has to be executed to get the identifier (e.g. "identity" generator, not "sequence"),
this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is not good in a long-running conversation with an extended Session/persistence context."
---------------------------------------------------------------------------------
簡單翻譯一下上邊的句子的主要內容:
1,persist把一個瞬態的例項持久化,但是並"不保證"識別符號被立刻填入到持久化例項中,識別符號的填入可能被推遲到flush的時間。
2,persist"保證",當它在一個transaction外部被呼叫的時候並不觸發一個Sql Insert,這個功能是很有用的,
當我們通過繼承Session/persistence context來封裝一個長會話流程的時候,一個persist這樣的函式是需要的。
3,save"不保證"第2條,它要返回識別符號,所以它會立即執行Sql insert,不管是不是在transaction內部還是外部
五,saveOrUpdateCopy,merge和update區別
首先說明merge是用來代替saveOrUpdateCopy的,這個詳細見這裡
然後比較update和merge
update的作用上邊說了,這裡說一下merge的
如果session中存在相同持久化標識(identifier)的例項,用使用者給出的物件的狀態覆蓋舊有的持久例項
如果session沒有相應的持久例項,則嘗試從資料庫中載入,或建立新的持久化例項,最後返回該持久例項
使用者給出的這個物件沒有被關聯到session上,它依舊是脫管的
重點是最後一句:
當我們使用update的時候,執行完成後,我們提供的物件A的狀態變成持久化狀態
但當我們使用merge的時候,執行完成,我們提供的物件A還是脫管狀態,hibernate或者new了一個B,或者檢索到
一個持久物件B,並把我們提供的物件A的所有的值拷貝到這個B,執行完成後B是持久狀態,而我們提供的A還是託管狀態
六,flush和update區別
這兩個的區別好理解
update操作的是在脫管狀態的物件
而flush是操作的在持久狀態的物件。
預設情況下,一個持久狀態的物件是不需要update的,只要你更改了物件的值,等待hibernate flush就自動
儲存到資料庫了。hibernate flush發生再幾種情況下:
1,呼叫某些查詢的時候
2,transaction commit的時候
3,手動呼叫flush的時候
七,lock和update區別
update是把一個已經更改過的脫管狀態的物件變成持久狀態
lock是把一個沒有更改過的脫管狀態的物件變成持久狀態
對應更改一個記錄的內容,兩個的操作不同:
update的操作步驟是:
(1)更改脫管的物件->呼叫update
lock的操作步驟是:
(2)呼叫lock把物件從脫管狀態變成持久狀態-->更改持久狀態的物件的內容-->等待flush或者手動flush
persist和merge: 沒有和資料庫進行同步
save和update: 處理後的資料處於持久狀態,換句話說,呼叫sql進行和資料庫同步的步驟。
總的來說,對於長事務的處理,應該使用persist和merge。減少資料庫互動。
總結如下:Session的幾個主要方法
1.save,persist儲存資料,persist在事務外不會產生insert語句。
2.delete,刪除物件
3.update,更新物件,如果資料庫中沒有記錄,會出現異常。
4.get,根據ID查,會立刻訪問資料庫。
5.Load,根據ID查,(返回的是代理,不會立即訪問資料庫)。
6.saveOrUpdate,merge(根據ID和version的值來確定是save或update),呼叫merge你的物件還是託管的。
7.lock(把物件變成持久物件,但不會同步物件的狀態)。