1. 程式人生 > 實用技巧 >hibernate中物件的3種狀態——瞬時態(Transient)、 持久態(Persistent)、脫管態(Detached)...

hibernate中物件的3種狀態——瞬時態(Transient)、 持久態(Persistent)、脫管態(Detached)...

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

hibernate的物件有3種狀態,分別為:瞬時態(Transient)、持久態(Persistent)、脫管態(Detached)。處於持久態的物件也稱為PO(Persistence Object),瞬時物件和脫管物件也稱為VO(Value Object)。

這3個狀態是hibernate裡pojo物件得3個狀態,個人覺得這個物件始終都是pojo,而在這3個狀態中得vo和po只是它這時得一個表象而已(即它這時得狀態和po或vo狀態相同),並不能就說它此時是一個vo或po物件。而且po是根據具體orm框架生成得象JDO和hibernate生成它得機制就不一樣。這裡說po只是廣義得描述一個狀態。

1.瞬時狀態(Transient)

當我們通過Java的new關鍵字來生成一個實體物件時,這時這個實體物件就處於自由狀態,如下:

Customer customer=new Customer(“zx”,27,images);

這時customer物件就處於自由狀態,為什麼說customer物件處於自由狀態呢?這是因為,此時customer只是通過JVM獲得了一塊記憶體空間,還並沒有通過Session物件的save()方法儲存進資料庫,因此也就還沒有納入Hibernate的快取管理中,也就是說customer物件現在還自由的遊蕩於Hibernate快取管理之外。所以我們可以看出自由物件最大的特點就是,在資料庫中不存在一條與它對應的記錄。

瞬時物件特點:

(1)不和Session例項關聯

(2)在資料庫中沒有和瞬時物件關聯的記錄

2.持久狀態(Persistent)

持久化物件就是已經被儲存進資料庫的實體物件,並且這個實體物件現在還處於Hibernate的快取管理之中。這是對該實體物件的任何修改,都會在清理快取時同步到資料庫中。如下所示:

Customer customer=new Customer(“zx”,27,images);

tx=session.beginTransaction();

session.save(customer);

customer=(Customer)session.load(Customer.class,”1”);

customer.setAge(28);

tx.commit();

這時我們並沒有顯示呼叫session.update()方法來儲存更新,但是對實體物件的修改還是會同步更新到資料庫中,因為此時customer物件通過save方法儲存進資料庫後,已經是持久化物件了,然後通過load方法再次載入它,它仍然是持久化物件,所以它還處於Hibernate快取的管理之中,這時當執行tx.commit()方法時,Hibernate會自動清理快取,並且自動將持久化物件的屬性變化同步到到資料庫中。

持久的例項在資料庫中有對應的記錄,並擁有一個持久化標識(identifier).

持久物件總是與Session和Transaction相關聯,在一個Session中,對持久物件的改變不會馬上對資料庫進行變更,而必須在Transaction終止,也就是執行commit()之後,才在資料庫中真正執行SQL進行變更,持久物件的狀態才會與資料庫進行同步。在同步之前的持久物件稱為髒(dirty)物件。

瞬時物件轉為持久物件:

(1)通過Session的save()和saveOrUpdate()方法把一個瞬時物件與資料庫相關聯,這個瞬時物件就成為持久化物件。

(2)使用fine(),get(),load()和iterater()待方法查詢到的資料物件,將成為持久化物件。

持久化物件的特點:

(1)和Session例項關聯

(2)在資料庫中有和持久物件關聯的記錄

3.脫管狀態(Detached)

當一個持久化物件,脫離開Hibernate的快取管理後,它就處於遊離狀態,遊離物件和自由物件的最大區別在於,遊離物件在資料庫中可能還存在一條與它對應的記錄,只是現在這個遊離物件脫離了Hibernate的快取管理,而自由物件不會在資料庫中出現與它對應的資料記錄。如下所示:

Customer customer=new Customer(“zx”,27,images);

tx=session.beginTransaction();

session.save(customer);

customer=(Customer)session.load(Customer.class,”1”);

customer.setAge(28);

tx.commit();

session.close();

當session關閉後,customer物件就不處於Hibernate的快取管理之中了,但是此時在資料庫中還存在一條與customer物件對應的資料記錄,所以此時customer物件處於遊離態

與持久物件關聯的Session被關閉後,物件就變為脫管物件。對脫管物件的引用依然有效,物件可繼續被修改。

脫管物件特點:

(1)本質上和瞬時物件相同

(2)只是比愛瞬時物件多了一個數據庫記錄標識值id.

持久物件轉為脫管物件:

當執行close()或clear(),evict()之後,持久物件會變為脫管物件。

瞬時物件轉為持久物件:

通過Session的update(),saveOrUpdate()和lock()等方法,把脫管物件變為持久物件。

三種狀態相互轉化的狀態圖如下:

Hibernate三種狀態

4.結合save(),update(),saveOrUpdate()方法說明物件的狀態

(1)Save()方法將瞬時物件儲存到資料庫,物件的臨時狀態將變為持久化狀態。當物件在持久化狀態時,它一直位於Session的快取中,對它的任何操作在事務提交時都將同步到資料庫,因此,對一個已經持久的物件呼叫save()或update()方法是沒有意義的。如:

Student stu = new Strudnet();

stu.setCarId(“200234567”);

stu.setId(“100”);

//開啟Session,開啟事務

session.save(stu);

stu.setCardId(“20076548”);

session.save(stu);//無效

session.update(stu); //無效

//提交事務,關閉Session

(2)update()方法兩種用途重新關聯脫管物件為持久化狀態物件,顯示呼叫update()以更新物件。呼叫update()只為了關聯一個脫管物件到持久狀態,當物件已經是持久狀態時,呼叫update()就沒有多大意義了。如:

//開啟session,開啟事務

stu = (Student)session.get(Student.class,”123456”);

stu.setName(“Body”);

session.update(stu);//由於stu是持久物件,必然位於Session緩衝中,

對stu所做的變更將//被同步到資料庫中。所以update()是沒有意義的,可以不要這句效果一樣的。

//提交事務,關閉Session

Hibernate總是執行update語句,不管這個脫管物件在離開Session之後有沒有更改過,在清理快取時Hibernate總是傳送一條update語句,以確保脫管物件和資料庫記錄的資料一致,如:

Student stu = new Strudnet();

stu.setCarId(“1234”);

//開啟Session1,開啟事務

session1.save(stu);

//提交事務,關閉Session1

stu.set(“4567”);//對脫管物件進行更改

//開啟Session2,開啟事務

session2.update(stu);

//提交事務,關閉Session2

注:即使把session2.update(stu);這句去掉,提交事務時仍然會執行一條update()語句。

如果希望只有脫管物件改變了,Hibernate才生成update語句,可以把對映檔案中<class>標籤的select-before-update設為true,這種會先發送一條select語句取得資料庫中的值,判斷值是否相同,如果相同就不執行update語句。不過這種做法有一定的缺點,每次update語句之前總是要傳送一條多餘的select語句,影響效能。對於偶爾更改的類,設定才是有效的,對於經常要更改的類這樣做是影響效率的。

(3)saveOrUpdate()方法兼具save()和update()方法的功能,對於傳入的物件,saveOrUpdate()首先判斷其是脫管物件還是臨時物件,然後呼叫合適的方法。

轉載於:https://my.oschina.net/airship/blog/829554