【Hibernate】從0開始學Hibernate--002。Hibernate*Session詳解

Hibernate從0開始,第一部分初涉Hibernate搭建第一個簡單的Hibernate框架

https://blog.csdn.net/hekaikai666/article/details/81672688

回顧與總結:

簡述上一章的主要內容:

(一)Hibernate框架的概念:數據持久層的ORM框架,主要作用是用於操作數據庫,簡化封裝了JDBC的操作

(二)Hibernate框架的優點:開發效率高、可移植性好、完全面向對象、多表級聯操作、精細數據緩存、延遲加載。

(三)Hibernate框架的缺點:特定SQL語句優化、大規模批量數據處理

(四)ORM對象映射關係:Hibernate屬於第四級(一共四級)

(五)Hibernate框架使用步驟:

        1、創建數據庫;

        2、創建項目並導入兩大核心包;

        3、導入Hibernate主配置文件;

        4、根據數據庫中的表創建相應的實體類;

        5、編寫映射文件;

        6、加載映射文件;

        7、執行相關數據庫操作;

接下來,我們就應該學習如何操作數據庫。首先要了解幾個概念:SessionFactory和Session和Configuration,這三個都是Hibernate操作做數據庫常用的接口,那麼他們究竟是用來幹什麼的呢?

Session接口:

    Session接口對於Hibernate以至於開發人員來說是一個非常重要的接口。Hibernate中,實例化的Session是的接口類,創建和銷燬它都不會佔用很多資源。這在實際項目 中確實很重要,因爲在客戶程序中,可能會不斷地創建以及銷燬Session對象,如果Session的開銷太大,會給系統帶來不良影響。但值得注意的是 Session對象是非線程安全的,因此在你的設計中,最好是一個線程只創建一個Session對象。   
    在Hibernate的設計者的腦中,他們將session看作介於數據連接與事務管理一種中間接口。我們可以將session想象成一個持久化對象的緩衝區,Hibernate能檢測到這些持久對象的改變,並及時刷新數據庫。我們有時也稱Session是一個持久層管理器,因爲它包含這一些持久層相關的操作,諸如存儲持久對象至數據庫,以及從數據庫從獲得它們。區別於JSP九大內置對象中的session,Hibernate的session不同於JSP應用中的HttpSession。當我們使用session這個術語時,我們指的是Hibernate中的session,我將HttpSesion對象稱爲用戶session。   

SessionFactory接口:

    這裏用到了一個設計模式――工廠模式,用戶程序從工廠類SessionFactory中取得Session的實例。(之後會詳細的講Java中的6中設計原則和23種設計模式)
    SessionFactory並不是輕量級的!實際上它的設計者的意圖是讓它能在整個應用中共享。典型地來說,一個項目通常只需要一 個SessionFactory就夠了,但是當你的項目要操作多個數據庫時,那你必須爲每個數據庫指定一個SessionFactory。 所以SessionFactory中就是用來操作各種session的,具體詳解到下貼中關於緩存機制。  SessionFactory在Hibernate中實際起到了一個緩衝區的作用,它緩衝了Hibernate自動生成的SQL語句和一些其它的映射數據,還緩衝了一些將來有可能重複利用的數據。   

Configuration接口 :

Configuration接口的作用是對Hibernate進行配置,以及對它進行啓動。在Hibernate的啓動過程中,Configuration類的實例首先定位映射文檔的位置,讀取這些配置,然後創建一個SessionFactory對象。相當於在Java類中繼承關係,而Configuration就是用來與SessionFactory來繼承操作的。

一、Session操作數據庫。

        首先我們瞭解幾個代名詞: 

       DML--指的是數據操縱語言,eg:insert into ,update ,delete
       DQL--數據庫查詢語言,  eg:select
       DDL--數據庫模式定義語言   eg:create   alter    drop
       DCL==數據庫控制語言    eg:grant     revoke
       TCL--事務控制語言    eg:commit
       DDL,DML,DCL,DQL,TCL共同組成數據庫的完整語言。

        (一)那麼我們的DML數據操作語言就是基礎操作數據庫的語言,主要實現的功能是增、刪、改的語句,他們有一個共同的特點:數據操作需要開啓和關閉事務。當然也需要事務控制語句來提交。

       首先提出一個獲取工廠類的方法:因爲使用session就需要創建項目有且僅有唯一的一個SessionFactory工廠。

public static SessionFactory getSessionFactory() {
	// 實例化主配置加載Configuration類對象
	Configuration cf = new Configuration();
	// 加載項目主配置文件
	cf.configure("hibernate.cfg.xml");
	// 獲取sessionFactory工廠對象
	SessionFactory factory = cf.buildSessionFactory();
	// 返回SessionFactory對象
	return factory;
}

       數據庫增加操作:session.save(Object);需要注意的是添加事務要進行提交,任何執行都需要Session對象關閉。

/**
 * 通過session對象添加數據
 * 
 * @param factory
 *            sessionFactory工廠對象
 */
 private static void insert(SessionFactory factory) {
 	// 通過工廠獲取Session 對象
	Session session = factory.openSession();
	// 使用對象開啓事務
	Transaction begin = session.beginTransaction();
	// 創建一個實體對象
	Dept dept = new Dept(2, "凱寶寶自造有限公司", "西安");
	// 使用Session往數據庫中插入一條數據
	session.save(dept);
	// 提交事務
	begin.commit();
	// 關閉session
	session.close();
 }

         數據庫刪除操作:session.delete(Object);需要注意的是刪除事務要進行提交,任何執行都需要Session對象關閉,刪除需要操作2條SQL語句,第一句是查詢此條,然後執行第二條刪除。

/**
 * 通過session對象刪除數據
 * 
 * @param factory
 *            sessionFactory工廠對象
 */
 private static void delete(SessionFactory factory) {
	// 獲取session對象
	Session session = factory.openSession();
	// 開啓事務
	Transaction begin = session.beginTransaction();
	// 根據id查找要刪除的對象
	Dept dept = (Dept) session.get(Dept.class, 3);
	// 執行刪除
	session.delete(dept);
	// 提交事務
	begin.commit();
	// 關閉session
	session.close();
}

        數據庫修改操作:session.(); 需要注意的是,數據庫先進行查詢,然後進行數據刪除,在把新的數據加入,所以需要執行3條SQL語句。

/**
 * 通過session對象修改數據
 * 
 * @param factory
 *            sessionFactory工廠對象
 */
 private static void update(SessionFactory factory) {
	// 通過工廠獲取Session 對象
	Session session = factory.openSession();
	// 使用對象開啓事務
	Transaction begin = session.beginTransaction();
	// 創建一個對象
	Dept dept = new Dept(3, "凱寶寶自造有限公司", "美國");
	// 修改數據:先查詢表中是否有這條數據,沒有就插入,有就看數據是否一致,一致不做任何操作,如果不一致就執行操作修改
	session.update(dept);
	// 提交事務
	begin.commit();
	// 關閉session
	session.close();
 }

        數據庫保存並修改:session.saveOrUpdate(Object);先查詢表中是否有這條數據,沒有就插入,有就看數據是否一致,一致不做任何操作,如果不一致就執行操作修改

/**
 * 通過session對象修改數據
 * 
 * @param factory
 *            sessionFactory工廠對象
 */
 private static void update(SessionFactory factory) {
	// 通過工廠獲取Session 對象
	Session session = factory.openSession();
	// 使用對象開啓事務
	Transaction begin = session.beginTransaction();
	// 創建一個對象
	Dept dept = new Dept(3, "凱寶寶自造有限公司", "美國");
	// 修改數據:先查詢表中是否有這條數據,沒有就插入,有就看數據是否一致,一致不做任何操作,如果不一致就執行操作修改
	session.saveOrUpdate(dept);
	// 提交事務
	begin.commit();
	// 關閉session
	session.close();
 }

        (二)數據庫簡單的查詢操作:根據ID查詢一條屬性(對象中),數據庫中則需要調用兩個方法get() 或 load();

                get():只要調用此方法就會立即向數據庫發送一條查詢語句;並可以返回查詢結果對象;屬於非延遲加載機制,當無法查詢到此id對應的對象數據時,會報出一個NullPointerException空指針異常。

                load():只要訪問對象的非查詢屬性(ID)纔會對數據庫進行發送操作,屬於延遲加載機制。當無法查詢到此id對應的數據時,會報出一個ObjectNotFoundException對象未找到異常。

/**
     * 根據ID查詢一個對象. 
     * 
     * @param factory
     *            sessionFactory工廠對象
     */
    private static void select1(SessionFactory factory) {
	// 獲取session對象
	Session session = factory.openSession();
	// 直接id查詢一個對象
	Dept dept1 = (Dept) session.get(Dept.class, 10);
        Dept dept = (Dept) session.load(Dept.class, 10);
        System.out.println("load:"+dept.getDname());
	// session中get和load的區別
	// get只要調用get方法,就會把所有的字段加載到內存中,如果訪問不在id範圍內的屬性則會NullPointerException(空指針異常)
	// load只要使用了返回的對象,纔會運行加載的方法(訪問非ID屬性)如果訪問不在id範圍內的屬性則會ObjectNotFoundException(對象未找到異常)
}

對於Session查詢獲取中使用get()和load()方法,當然會呈現不同的狀態,而在session中會有三中不同的對象存儲方式:臨時狀態、持久狀態、遊離狀態。

二、Hibernate中對象存儲的三種狀態。

        a.臨時狀態:臨時狀態對象(瞬時態) 內存中有對象,數據庫中沒有與之相對應的數據

        b.持久狀態:內存中有對象,數據庫中有與之對應的數據,當修改對象的屬性時,數據庫中的數據也會跟着自動更改

        c.遊離狀態:遊離狀態對象 內存中有對象,數據庫中有與之對應的數據,但是對象處理離線狀態,修改對象的屬性,數據庫中數據不會跟着被修改

/**

* 臨時狀態對象(瞬時態) 內存中有對象,數據庫中沒有與之相對應的數據

* 什麼樣的對象是臨時狀態?新創建的對象;持久狀態的對象調用了delete()方法

*/

/**

* 持久狀態對象 內存中有對象,數據庫中有與之對應的數據,當修改對象的屬性時,數據庫中的數據也會跟着自動更改(緩存在session緩存中...)

* 什麼樣的對象是持久狀態的對象?新創建的對象調用了save()或者saveOrUpdate();通過get()或者load()方法從數據庫中加載出來的對象;遊離態對象調用了update或者saveOrUpdate將變回持久態

*/

 

/**

* 遊離狀態對象 內存中有對象,數據庫中有與之對應的數據,但是對象處理離線狀態,修改對象的屬性,數據庫中數據不會跟着被修改

* 什麼樣的對象是遊離態呢?session關閉時(.close());從session緩存中踢出了某個持久態對象(.evick());清空session緩存(.clear())

*/

臨時狀態和遊離狀態隨時都有可能被垃圾回收...

上面這些文字相信你也雲裏霧裏,那麼下面我來用一張圖來詳細解釋一下這三種狀態的轉換關係。

 

 當創建new()一個新的對象的時候,所創建的對象就處於臨時狀態,此時的對象存儲與內存當中當調用了save()(非延遲加載)或者saveOrUpdate()(延遲加載,需要使用非查詢屬性之後方可執行)方法之後。與數據庫產生交互,對象也就變成持久狀態,在內存中和在數據庫中均有對象屬性存在,此時執行修改的方法,內存中和數據庫中的數據均做修改。當對象調用delete()方法後,刪除掉數據庫中的數據,對象中的屬性也就變成了臨時態,但是臨時態是不會被清理的。當session對象關閉,清除或者踢出的方法時,持久態的屬性也就變成了遊離態(對象依舊在內存中,但是與數據庫的連接已經斷開,所以執行增刪改的方法只會影響對象不會影響數據庫中的內容)當重新建立連接(創建新的session對象後)調用save()或者saveOrUpdate()方法,又將變成持久態。當程序關閉的時候,也就是遊離態的對象無法再進行操作的時候,就只能等待PC的垃圾處理機制,隨機的清理掉對象的屬性,但不會影響到數據庫的操作。

三、髒數據與刷新緩存

        什麼是髒數據?爲什麼存在髒數據?

        髒數據:當session緩存中持久態對象的數據發生了變化,而數據庫中的數據未發生改變,這個對象是髒對象(髒數據)。在數據庫技術中,髒數據在臨時更新(髒讀)中產生。事務A更新了某個數據項X,但是由於某種原因,事務A出現了問題,於是要把A回滾。但是在回滾之前,另一個事務B讀取了數據項X的值(A更新後),A回滾了事務,數據項恢復了原值。事務B讀取的就是數據項X的就是一個“臨時”的值,就是髒數據。

        爲了針對出現髒數據的問題,session中有一種檢查機制,使數據庫中的數據與對象中的數據保持一致,就叫做髒檢查;髒檢查就是檢查數據庫中數據是否和session緩存中持久態對象數據一致,如果不一致,則在刷新緩存時,將數據庫中數據刷新爲與session緩存中一致。一句話:刷新數據庫中的數據和session對象中的數據保持一致

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章