Hibernate物件狀態

Red88Army發表於2020-04-06
Hibernate物件狀態
在hibernate中有三種狀態:瞬時態(Transient)、 持久態(Persistent)、脫管態(Detached)。處於持久態的物件也稱為PO(Persistence Object),瞬時物件和脫管物件也稱為VO(Value Object)。
通過自己在網上的搜尋,也瞭解到,這三種狀態也可以稱作:臨時狀態、持久狀態、遊離狀態。
一、三種狀態介紹:
(1) 瞬時狀態:
由new操作符建立,且尚未與Hibernate Session關聯的物件被認定為瞬時(Transient)的。瞬時(Transient)物件不會被持久化到資料庫中,也不會被賦予持久化標識(identifier)。如果瞬時(Transient)物件在程式中沒有被引用,它會被垃圾回收器(garbage collector)銷燬。使用Hibernate Session可以將其變為持久(Persistent)狀態。(Hibernate會自動執行必要的SQL語句)。
瞬時狀態的特點有:
1、 與資料庫中的記錄沒有任何關聯,也就是沒有與其相關聯的資料庫記錄。
2、 與Session沒有任何關係,也就是沒有通過Session物件的例項對其進行任何持久化的操作。

舉例:
User user=new User(); //user是一個瞬時物件,在資料庫的表中是沒有記錄和該物件相對應的。和session沒有關係。
user.setName(“ddd”);
user.setBirthday(new Date());

session.save(user); //持久化狀態



(2) 持久狀態:
持久(Persistent)是例項在資料庫中有對應的記錄,並擁有一個持久化標識(identifier)。持久(Persistent)的例項可能是剛被儲存的,或剛被載入的,無論哪一種,按定義,它存在於相關聯的Session作用範圍內。Hibernate會檢測到處於持久(Persistent)狀態的物件的任何改動,在當前操作單元(unit of work)執行完畢時將物件資料(state)與資料庫同步(synchronize)。開發者不需要手動執行Update。將物件從持久(Persistent)狀態程式設計瞬時(Transient)狀態同樣也不需要手動執行delete語句。
持久物件具有如下特點:
1、 和session例項關聯;
2、 在資料庫中有與之關聯的記錄。
3、 Hibernate會根據持久態物件的屬性的變化而改變資料庫中的相應記錄。
舉例:
Session session = factory.openSession();
Transaction tx = session.beginTransaction();

session.save(stu); // persistent持久化狀態
System.out.println(stu);

tx.commit();
session.close(); //執行close()方法之後,就會由持久物件轉換成脫管物件

System.out.println(stu); // 脫管物件


(3)脫管狀態:
與持久(Persistent)狀態物件關聯的Session被關閉後,物件就變為脫管(Detached)的。對脫管(Detached)物件的引用依然有效,物件可繼續被修改。脫管(Detached)物件如果重新關聯到某個新的Session上,會再次轉變為持久(Transistent)的(在脫管Detached其間的改動將被持久化到資料庫)。這個功能使得一種程式設計模型,即中間會給使用者思考時間(user think-time)的長時間執行的操作單元(unit of work).
脫管物件擁有資料庫的識別值,可通過update()、saveOrUpdate()等方法,轉變成持久物件。
脫管物件具有如下特點:
1、 本質上與瞬時物件相同,在沒有任何變數引用它時,JVM會在適當的時候將它回收;
2、 比瞬時物件多了一個資料庫記錄標識值。
3、 不在於Session相關聯。
4、 脫管物件一定是由持久態物件轉化而來。
首先是我們的UML圖轉換:以及解析:

[img]http://dl.iteye.com/upload/attachment/604687/bd2e06d1-e62c-3dfe-aa35-12b0092c2048.bmp[/img]


對以上圖形的解析:
1、當一個物件被new了以後此物件處於瞬時態(Transient);
2、然後對此物件執行session的save() 或者saveOrUpdate()方法後,此物件被放入session的一級快取進入持久態.
2、當再對此物件執行evict()/close()/clear()的操作後此物件進入遊離態(Detached)
4、遊離態(Detached)和瞬時態(Transient)的物件由於沒有被session管理會在適當的時機被java的垃圾回收站(garbage)回收.
5、執行session的get()/load()/find()/iternte()等方法從資料庫裡查詢的到的物件,處於持久態(Persistent).
6、當對資料庫中的紀錄進行update()/saveOrUpdate()/lock()操作後遊離態的物件就過渡到持久態 
7、處於持久態(Persistent)與遊離態(Detached)的物件在資料庫中都有對應的記錄.
8、瞬時態(Transient)與遊離態(Detached)的物件都可以被回收可是瞬時態的物件在資料庫中沒有對應的紀錄,而遊離態的物件在資料庫中有對用的紀錄。

物件狀態的總結:(如下圖所示)

[img]http://dl.iteye.com/upload/attachment/604689/ce10c0fd-6863-3074-abac-aa9913012a40.bmp[/img]

1、操縱持久化物件-save()
(1)Session 的 save() 方法使一個臨時物件轉變為持久化物件
(2)Session 的 save() 方法完成以下操作:
(3)把 News 物件加入到 Session 快取中, 使它進入持久化狀態
(4)選用對映檔案指定的識別符號生成器, 為持久化物件分配唯一的 OID. 在使用代理主鍵的情況下, setId() 方法為 News 物件設定 OID 使無效的.
(5)計劃執行一條 insert 語句,把Customer物件當前的屬性值組裝到insert語句中
(6)Hibernate 通過持久化物件的 OID 來維持它和資料庫相關記錄的對應關係. 當 News 物件處於持久化狀態時, 不允許程式隨意修改它的 ID
2、 操縱持久化物件-update()
(1)Session 的 update() 方法使一個遊離物件轉變為持久化物件, 並且計劃執行一條 update 語句.
[img]http://dl.iteye.com/upload/attachment/604695/227322e8-d8d5-32cb-b849-2e1727749f05.bmp[/img]



3、操縱持久化物件-saveOrupdate()
saveOrUpdate:
該方法同時包含save和update方法,如果引數是臨時物件就用save方
法,如果是遊離物件就用update方法,如果是持久化物件就直接返回。
如果引數是臨時物件就用save方法

[img]http://dl.iteye.com/upload/attachment/604697/ece95fa7-2a72-367e-a85b-d889f90c432b.bmp[/img]


如果是遊離物件就用update方法

[img]http://dl.iteye.com/upload/attachment/604703/5ea78045-0a2c-37fd-a7fb-e9b04a6dfd7a.bmp[/img]


如果是持久化物件就直接返回,不執行操作

[img]http://dl.iteye.com/upload/attachment/604706/be95b6da-c7f7-31a8-a3cd-668cc4406229.bmp[/img]


二、使物件持久化:
Hibernate認為持久化類(persistent class)新例項化的物件是瞬時(Transient)的。我們可以通過將瞬時(Transient)物件與session關聯而把它變為持久(Persistent)的。
DomesticCat fritz=new DomesticCat();
fritz.setColor(Color.GINGER);
fritz.setSex(‘M’);
fritz.setName(“Fritz”);
Long generatedId=(Long) sess.save(frize);


如果Cat的持久化標識(identifier)是generated型別的,那麼該標識(indentifier)會自動在save()被呼叫時產生並分配給cat。如果Cat的持久化標識(identifier)是addigned型別的,或是一個複合主鍵(composite key),那麼該標識(identifier)應當在呼叫save()之前手動賦予給cat。你也可以按照EJB3 early draft中定義的語句,使用persist()替代save()。
(1) persist()使一個臨時例項持久化。然而,它不保證立即把標示符值分配給永續性例項,這會發生在沖刷(flush)的時候。Persist()也保證它在事務邊界外呼叫時不會執行insert語句。這對於長期執行的帶有擴充套件會話/持久化上下文的會話是很游泳的。
(2) save()保證返回一個標示符。如果需要執行insert來獲取標示符(如“identity”而非“sequence”生成器),這個insert將立即執行,不管你是否在事務內部還是外部。這對於長期執行的帶有擴充套件會話/持久上下文的會話來說會出現問題。
此外,你可以用一個過載版本的save()方法。

相關文章