Hibernate中的對象有三種狀態:臨時狀態 (Transient),持久狀態 (Persistent),遊離狀態(Detached)java
1. session三種狀態:sql
1. 1.臨時狀態(Transient)數據庫
由 new 命令開闢內存空間的 Java 對象,也就是平時所熟悉的普通 Java 對象,該對象未曾進行持久化,未與任何Session相關聯,也叫自由態,只存在於內存中,而在數據庫中沒有相應數據。用new建立的對象,它沒有持久化,沒有處於Session中,處於此狀態的對象叫臨時對象;緩存
如: Student stu = new Student();session
臨時對象特色:ide
(1) 不和 Session 實例關聯性能
(2) 在數據庫中沒有和臨時對象關聯的記錄ui
2. 2. 持久狀態 (Persistent)spa
持久的實例在數據庫中有對應的記錄,並擁有一個持久化標識 (identifier).該對象與session關聯而且在數據庫中有相應數據。已經持久化,加入到了Session緩存中。如經過hibernate語句保存的對象。處於此狀態的對象叫持久對象;hibernate
持久對象老是與 Session 和 Transaction 相關聯,在一個 Session 中,對持久對象的改變不會立刻對數據庫進行變動,而必須在Transaction 終止,也就是執行 commit() 以後,纔在數據庫中真正運行 SQL 進行變動,持久對象的狀態纔會與數據庫進行同步。在同步以前的持久對象稱爲髒 (dirty) 對象。
臨時對象轉爲持久對象:
(1) 經過 Session 的 save() 和 saveOrUpdate() 方法把一個臨時對象與數據庫相關聯,這個臨時對象就成爲持久化對象。
(2) 使用 fine(),get(),load() 和 iterater() 待方法查詢到的數據對象,將成爲持久化對象。
持久化對象的特色:
(1) 和 Session 實例關聯
(2) 在數據庫中有和持久對象關聯的記錄
3. 3. 遊離狀態 (Detached)
與持久對象關聯的 Session 被關閉後,對象就變爲遊離對象。對遊離對象的引用依然有效,對象可繼續被修改。
持久化對象脫離了Session的對象。如Session緩存被清空的對象。該對象已經持久化,但不在Session緩存中。處於此狀態的對象叫遊離對象;;
遊離對象特色:
(1) 本質上和臨時對象相同
(2) 只是臨時對象多了一個數據庫記錄標識值 id.
持久對象轉爲遊離對象:
當執行 close() 或 clear(),evict() 以後,持久對象會變爲遊離對象。
遊離對象轉爲持久對象:
經過 Session 的 update(),saveOrUpdate() 和 lock() 等方法,把遊離對象變爲持久對象。
遊離對象和臨時對象異同:
二者都不會被Session關聯,對象屬性和數據庫可能不一致;
遊離對象有持久化對象關閉Session而轉化而來,在內存中還有對象因此此時就變成遊離狀態了;
Hibernate和SQL的關係:
在操做了hibernate的方法如save()等後,並無直接生成sql語句,去操做數據庫,而是把這些更新存入Session中,只有Session緩存要被更新時,底層的sql語句才能執行,數據存入數據庫;
三種狀態相互轉化的狀態圖以下:
4 .結合 save(),update(),saveOrUpdate() 方法說明對象的狀態
(1)Save() 方法將臨時對象保存到數據庫,對象的臨時狀態將變爲持久化狀態。當對象在持久化狀態時,它一直位於 Session 的緩存中,對它的任何操做在事務提交時都將同步到數據庫,所以,對一個已經持久的對象調用 save() 或 update() 方法是沒有意義的。如:
Student stu = new Strudnet();
stu.setCarId(「200234567」);
stu.setId(「100」);
Session session = HibernateUtil.getSessionFactory().getCurrentSession();// 打開 Session
session.beginTransaction();// 開啓事務
session.save(stu);
stu.setCardId(「20076548」);
session.save(stu); // 無效
session.update(stu); // 無效
session.getTransaction().commit();// 提交事務,
session.close();關閉 Session
(2)update() 方法兩種用途從新關聯遊離對象爲持久化狀態對象,顯示調用 update() 以更新對象。調用 update() 只爲了關聯一個遊離對象到持久狀態,當對象已是持久狀態時,調用 update() 就沒有多大意義了。如:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();// 打開 Session
session.beginTransaction();// 開啓事務
stu = (Student)session.get(Student.class,」123456」);
stu.setName(「Body」);
session.update(stu); // 因爲 stu 是持久對象,必然位於 Session 緩衝中,對 stu 所作的變動將 // 被同步到數據庫中。因此 update() 是沒有意義的,能夠不要這句效果同樣的。
session.getTransaction().commit();// 提交事務,
session.close();關閉 Session
Hibernate 老是執行 update 語句,無論這個遊離對象在離開 Session 以後有沒有更改過,在清理緩存時 Hibernate 老是發送一條update 語句,以確保遊離對象和數據庫記錄的數據一致。
如:
Student stu = new Strudnet();
stu.setCarId(「1234」);
Session session1 = HibernateUtil.getSessionFactory().getCurrentSession();// 打開 Session
session1.beginTransaction();// 開啓事務
session1.save(stu);
session1.getTransaction().commit();// 提交事務,
session1.close();關閉 Session
stu.set(「4567」); // 對遊離對象進行更改
Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();// 打開 Session
session2.beginTransaction();// 開啓事務
session2.update(stu);
session2.getTransaction().commit();// 提交事務,
session2.close();關閉 Session
注:即便把 session2.update(stu); 這句去掉,提交事務時仍然會執行一條 update() 語句。
若是但願只有脫管對象改變了, Hibernate 才生成 update 語句,能夠把映射文件中 <class> 標籤的 select-before-update 設爲true, 這種會先發送一條 select 語句取得數據庫中的值,判斷值是否相同,若是相同就不執行 update 語句。不過這種作法有必定的缺點,每次 update 語句以前老是要發送一條多餘的 select 語句,影響性能。對於偶爾更改的類,設置纔是有效的,對於常常要更改的類這樣作是影響效率的。
(3)saveOrUpdate() 方法兼具 save() 和 update() 方法的功能,對於傳入的對象, saveOrUpdate() 首先判斷其是脫管對象仍是臨時對象,而後調用合適的方法。
注:並不是到事務提交纔對數據庫操做,提交只是把變動持久化,實際上經過flush是能夠操做的,只是這個變動只能在本事務看到而已。
一,Session.save(user)運行機理。
1,把User對象加入緩存中,使它變成持久化對象;
2,選用映射文件指定的標識生成ID;
3,在Session清理緩存時候執行:在底層生成一個insert sql語句,把對象存入數據庫;
注意:在你執行Session.save(user)後,在Session清理緩存前,若是你修改user對象屬性值,那麼最終存入數據庫的值將是最後修改的值;此過程當中ID不能被修改;
二,Session.delete(user)運行過程。
若是user是持久化對象,則執行刪除操做,一樣底層數據庫的執行條件是:在Session清理緩存時候;
若是user是遊離對象:
1,將user對象和Session關聯,使之成爲持久化對象;
2,而後按照user 是持久化對象的過程執行;
三態之間的轉換方法:
①如何成爲自由態?
對象經過構造方法成爲自由態;持久態和遊離態則經過session的delete方法成爲自由態
②如何成爲持久態?
對象能夠由session的load或get方法直接成爲持久態;自由態對象能夠經過save,saveOrUpdate或persist方法成爲持久態;遊離態對象則能夠經過update,saveOrUpdate成爲持久態
③如何成爲遊離態?
遊離態只能由持久態轉換而來,經過close或clear方法實現。
即
臨時態轉換到持久態 save() saveOrUpdate()
持久態轉換到臨時態 delete()
持久態轉換到遊離態 evict() close() clear()
遊離態轉換到持久態 update() saveOrUpdate() lock()
幾種轉換方法的對比:
1.get 與load
都是從數據庫中加載數據封裝爲java對象,使得java對象從自由態直接變爲持久態;
可是有兩點區別:①get返回對象能夠爲null,load返回值則始終不爲null,找不到時會拋異常②get即時執行insert,而load則是在使用此對象時才執行insert
2.save,update與saveOrUpdate
save是將自由態轉爲持久態,而update是將遊離態轉爲持久態,saveOrUpdate能夠說是二者的綜合,它執行時先判斷對象的狀態(主要是經過有無主鍵判斷的),如果自由態,則save,如果遊離態,則update
3.save與persist
二者都是將對象由自由態轉爲持久態,但返回值不一樣:save返回主鍵值,而persist不返回
4,saveOrUpdate與merge
二者都是將自由態或遊離態對象與數據庫關聯,但merge不改變對象的原有狀態
此外,對clear與flush方法也做介紹。clear是將session中的對象所有變爲遊離態,是對象由持久態變爲遊離態的一種方法(另一種是關閉session);flush方法時爲了使update操做能即時進行(正常狀況下,只有在事務關閉時才進行update操做)。
Hibernate得到Session的兩個方法
你們都知道,使用Hibernate對數據進行操做最重要的是得到一個Session。
首先得到一個SessionFactory,經過.config().buildSessionFactory(),得到一個SessionFactory 進而取得Session的方法在Hibernate裏有兩種:
1:Session session = sessionFactory.openSession();
該種方法是建立一個新的session,不論當前的環境中是否已經建立,都會建立;
且當session提交成功後,須要手動關閉這個session;
2:Session session = sessionFactory.getCurrentSession();
該方法是獲取當前環境中的session,若環境中已經存在session,則取出當前的;若無session則建立一個新的,
只要當前的session提交後,該session會自動關閉,其後再使用getCurrentSession()方法,則是建立一個新的session;
使用以上兩種方式還須要注意的是事務控制,若是使用第一種方法,openSession()也許會致使數據的不一致,
例如在用戶管理功能模塊中,咱們對用戶的各類操做都須要作日誌記錄,此時要兩張數據表同時提交成功,不然都不進行數據的寫入;因此咱們要使用第二種方式來取得session。
特別強調:這兩種取得Session的方法不能混用。緣由很簡單,在Hibernate中,Session是一個接口。兩個獲取session的方法並不是是同一個實現,故不可混用!