SSH框架之-hibernate 三種狀態的轉換

1、遇到的神奇的事情

使用jpa操做數據庫,當我使用findAll()方法查處一個List的對象後,給對這個list的實體進行了一些操做,並無調用update 或者 saveOrUpdate方法,更改後的數據卻神奇的保存到數據庫裏面去了。java

最後簡單粗暴的解決辦法是把這份從數據裏面查出來的List 複製了一份,而後再操做,再返回。數據就正常了,數據庫也沒更新。後面找了資料才發現是jpa是對hibernate的封裝,底層是hibernate,這是hibernate的持久狀態搞的鬼。數據庫

2、hibernate 的三種狀態

1. 瞬時狀態 (Transient)緩存

當咱們經過Java的new關鍵字來生成一個實體對象時,這時這個實體對象就處於自由狀態,以下:session

1 Customer customer=new Customer(「zx」,27,images); 這時customer對象就處於自由狀態,爲何說customer對象處於自由狀態呢?這是由於,此時customer只是經過JVM得到了一塊內存空間,還並無經過Session對象的save()方法保存進數據庫,所以也就尚未歸入Hibernate的緩存管理中,也就是說customer對象如今還自由的遊蕩於Hibernate緩存管理以外。因此咱們能夠看出自由對象最大的特色就是,在數據庫中不存在一條與它對應的記錄。ssh

瞬時對象特色: 不和 Session 實例關聯 在數據庫中沒有和瞬時對象關聯的記錄ide

2. 持久狀態 (Persistent)性能

持久化對象就是已經被保存進數據庫的實體對象,而且這個實體對象如今還處於Hibernate的緩存管理之中。這是對該實體對象的任何修改,都會在清理緩存時同步到數據庫中。以下所示:學習

Customer customer=new Customer(「zx」,27,images);hibernate

tx=session.beginTransaction();cdn

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) 對象。

瞬時對象轉爲持久對象:

經過 Session 的 save() 和 saveOrUpdate() 方法把一個瞬時對象與數據庫相關聯,這個瞬時對象就成爲持久化對象。 使用 fine(),get(),load() 和 iterater() 待方法查詢到的數據對象,將成爲持久化對象。 持久化對象的特色:

和 Session 實例關聯 在數據庫中有和持久對象關聯的記錄 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 被關閉後,對象就變爲脫管對象。對脫管對象的引用依然有效,對象可繼續被修改。

脫管對象特色:

本質上和瞬時對象相同 只是比愛瞬時對象多了一個數據庫記錄標識值 id. 持久對象轉爲脫管對象:

當執行 close() 或 clear(),evict() 以後,持久對象會變爲脫管對象。

瞬時對象轉爲持久對象:

經過 Session 的 update(),saveOrUpdate() 和 lock() 等方法,把脫管對象變爲持久對象。

3、三種狀態的轉換

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);ssh

// 提交事務,關閉 Session2

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

若是但願只有脫管對象改變了, Hibernate 才生成 update 語句,能夠把映射文件中 標籤的 select-before-update 設爲 true, 這種會先發送一條 select 語句取得數據庫中的值,判斷值是否相同,若是相同就不執行 update語句。不過這種作法有必定的缺點,每次 update 語句以前老是要發送一條多餘的 select 語句,影響性能。對於偶爾更改的類,設置纔是有效的,對於常常要更改的類這樣作是影響效率的。

(3) saveOrUpdate() 方法兼具 save() 和 update() 方法的功能,對於傳入的對象, saveOrUpdate() 首先判斷其是脫管對象仍是臨時對象,而後調用合適的方法。

參考

Hibernate 實體對象的狀態及轉化 by javacoffe

注:喜歡的朋友能夠點贊加關注,一塊兒學習進步

相關文章
相關標籤/搜索