Hibernate框架深入學習

ORM思想:

首先我們來了解一下ORM思想:ORM的英文是Object Relation Mapping 對象關係映射。

對象-關係映射(OBJECT/RELATIONALMAPPING,簡稱ORM),是隨着面向對象的軟件開發方法發展而產生的。用來把對象模型表示的對象映射到基於S Q L 的關係模型數據庫結構中去。這樣,我們在具體的操作實體對象的時候,就不需要再去和複雜的 SQ L 語句打交道,只需簡單的操作實體對象的屬性和方法就可以了,O R M 技術是在對象和關係之間提供了一條橋樑,前臺的對象型數據和數據庫中的關係型的數據通過這個橋樑來相互轉化


簡單的說就是把我們程序中的實體類和數據庫表建立起來對應關係。

  所謂的ORM就是利用描述對象和數據庫表之間映射的元數據,自動把Java應用程序中的對象,持久化到關係型數據庫的表中。通過操作Java對象,就可以完成對數據庫表的操作。可以把ORM理解爲關係型數據和對象的一個紐帶,開發人員只需要關注紐帶一端映射的對象即可。




與其它操作數據庫的技術相比,Hibernate具有以下幾點優勢:

  1. HibernateJDBC訪問數據庫的代碼做了輕量級封裝,大大簡化了數據訪問層繁瑣的重複性代碼,並且減少了內存消耗,加快了運行效率。
  2. Hibernate是一個基於JDBC的主流持久化框架,是一個優秀的ORM實現,它很大程度的簡化了DAOData Access Object,數據訪問對象)層編碼工作。
  3. Hibernate的性能非常好,映射的靈活性很出色。它支持很多關係型數據庫,從一對一到多對多的各種複雜關係,可擴展性強,由於源代碼的開源以及API的開放,當本身功能不夠用時,可以自行編碼進行擴展。

明確關注:

Hibernate框架操作實體類就相當於操作數據庫表


Hibernate中get和load方法的區別

區別:

1、查詢的時機不一樣

get方法任何時候都是立即加載的,即只要一調用get馬上發起數據庫查詢

load方法默認情況下是延遲加載,即真正用到對象的非OID字段的數據才發起查詢

load方法可以通過配置的方式改爲立即加載。

配置的方式如下:

由於load方法是hibernate的方法所以只有XML的配置方式:(關閉懶加載的方式)

<class name="Customer" table="cst_customer" lazy="false">

2、返回的結果不一樣

get方法永遠返回查詢的實體類對象。

load方法當是延遲加載時,返回的是實體類的代理對象

涉及的概念:

立即加載:

是不管用不用馬上查詢。

延遲加載:

等到用的時候才真正發起查詢。


Hibernate的持久化類的概念:

Hibernate是持久層的ORM映射框架,專注於數據的持久化工作。所謂的持久化,就是將內存中的數據永久存儲到關係型數據庫中。那麼知道了什麼是持久化,什麼又是持久化類呢?其實所謂的持久化類指的是一個Java類與數據庫表建立了映射關係,那麼這個類稱爲是持久化類。其實你可以簡單的理解爲持久化類就是一個Java類有了一個映射文件與數據庫的表建立了關係


1.1.1 持久化類的編寫規則:

我們在編寫持久化類的時候需要有以下幾點需要注意:

  1. 持久化類需要提供無參數的構造方法。因爲在Hibernate的底層需要使用反射生成類的實例。
  2. 持久化類的屬性需要私有,對私有的屬性提供公有的getset方法。因爲在Hibernate底層會將查詢到的數據進行封裝。
  3. 持久化類的屬性要儘量使用包裝類的類型。因爲包裝類和基本數據類型的默認值不同,包裝類的類型語義描述更清晰而基本數據類型不容易描述。舉個例子:

假設表中有一員工工資的列

,如果使用double類型,如果這個員工工資忘記錄入到系統中,系統會將默認值0存入到數據庫,如果這個員工工資被扣完了,也會向系統中存入0.那麼這個0就有了多重含義,而如果使用包裝類類型就會避免以上情況,如果使用Double類型,忘記錄入工資就會存入null而不是0,而這個員工工資被扣完了,就會存入0,不會產生歧義。

    持久化類要有一個唯一標識OID與表的主鍵對應。因爲Hibernate中需要通過這個唯一標識OID區分在內存中是否是同一個持久化類。在Java中通過地址區分是否是同一個對象是一樣的意思,在關係型數據庫的表中是通過主鍵區分是否同一條記錄。那麼Hibernate就是通過這個OID來進行區分的。Hibernate是不允許在內存中出現兩個OID相同的持久化對象的。

    持久化類儘量不要使用final進行修飾。因爲Hibernate中有延遲加載的機制,這個機制中會產生代理對象,Hibernate產生代理對象使用的是字節碼的增強技術完成的,其實就是產生了當前類的一個子類對象實現的。如果使用了final修飾持久化類。那麼就不能產生子類,從而就不會產生代理對象,那麼Hibernate的延遲加載策略就會失效。

持久化類我們已經可以正常編寫了,但是在持久化類中需要有一個唯一標識OID與表的主鍵去建立映射關係。而且主鍵一般我們是不會讓客戶手動錄入的,一般我們是由程序生成主鍵。那麼Hibernate中也提供了相應的主鍵生成的方式,那麼我們來看下Hibernate的主鍵生成策略。

簡單的說:

我們的實體類都需要遵從JavaBean的編寫規範。

什麼是JavaBean:

Bean:在軟件開發領域,Bean表示可重用組件。

JavaBean就是用java語言開發的可重用組件。

JavaBean的編寫規範是什麼:

1.類都是public的(公有的,擁有最大的訪問權限,方便其他程序來調用)

2.都有默認無參構造函數(方便通過動態代理的方式來產生代理對象)

3.成員變量都是私有的(因爲這些屬性,我們並不希望外面來改變它,它只是服務於本程序的內部)

4.都有公有的get/set方法(方便外界使用)

5.一般都實現Serializable接口(方便對象的持久化操作,比如持久化到硬盤)

基本類型和包裝類的選擇問題:

由於包裝類可以有null值。所以實際開發中都是用包裝類。

1.1 hibernate中對象標識符(OID)Object Identify介紹

OID全稱是Object Identifier,又叫做對象標識符。

它是hibernate用於區分兩個對象是否是同一個對象的標識。

我們都知道,虛擬機內存區分兩個對象看的是內存的地址是否一致。數據庫區分兩個對象,靠的是表的主鍵。hibernate負責把內存中的對象持久化到數據庫表中,靠的就是對象標識符來區分兩個對象是否是同一個。實體類中映射主鍵的字段就是OID,如下圖所示:



1.1 hibernate的主鍵生成策略

在瞭解Hibernate的主鍵生成策略之前,先來了解兩個概念,即自然主鍵和代理主鍵,具體如下:

    自然主鍵:把具有業務含義的字段作爲主鍵,稱之爲自然主鍵。例如在customer表中,如果把name字段作爲主鍵,其前提條件必須是:每一個客戶的姓名不允許爲null,不允許客戶重名,並且不允許修改客戶姓名。儘管這也是可行的,但是不能滿足不斷變化的業務需求,一旦出現了允許客戶重名的業務需求,就必須修改數據模型,重新定義表的主鍵,這給數據庫的維護增加了難度。

    代理主鍵:把不具備業務含義的字段作爲主鍵,稱之爲代理主鍵。該字段一般取名爲“ID”,通常爲整數類型,因爲整數類型比字符串類型要節省更多的數據庫空間。在上面例子中,顯然更合理的方式是使用代理主鍵。

第1章 Hibernate的一級緩存和對象狀態

1.1 hibernate的一級緩存

1.1.1 hibernate中的一級緩存:

    Hibernate的一級緩存就是指Session緩存,Session緩存是一塊內存空間,用來存放相互管理的java對象,在使用Hibernate查詢對象的時候,首先會使用對象屬性的OID值在Hibernate的一級緩存中進行查找,如果找到匹配OID值的對象,就直接將該對象從一級緩存中取出使用,不會再查詢數據庫;如果沒有找到相同OID值的對象,則會去數據庫中查找相應數據。當從數據庫中查詢到所需數據時,該數據信息也會放置到一級緩存中。Hibernate的一級緩存的作用就是減少對數據庫的訪問次數,從而提升效率。

    在 Session 接口的實現中包含一系列的 Java 集合, 這些 Java 集合構成了 Session 緩存。只要 Session 實例沒有結束生命週期,存放在它緩存中的對象也不會結束生命週期。固一級緩存也被稱爲是Session基本的緩存。

Hibernate的一級緩存有如下特點:

1.當應用程序調用Session接口的save()、update()、saveOrUpdate時,如果Session緩存中沒有相應的對象,Hibernate就會自動的把從數據庫中查詢到的相應對象信息複製一份加入到一級緩存中去。

2.當調用Session接口的load()、get()方法,以及Query接口的iterator()方法時,會判斷緩存中是否存在該對象,有則返回,不會查詢數據庫,如果緩存中沒有要查詢對象,再去數據庫中查詢對應對象,並添加到一級緩存中。

3.當調用Session的close()方法時,Session緩存會被清空。

下面我們來提供一個測試Hibernate一級緩存的方法
  1. @Test  
  2.     // 證明Hibernate的一級緩存的存在:  
  3.     public void demo1(){  
  4.         Session session = HibernateUtils.openSession();  
  5.         Transaction tx = session.beginTransaction();          
  6.         Customer customer1 = session.get(Customer.class, 1l);// 馬上發生一條sql查詢1號客戶.並將數據存入了一級緩存  
  7.         System.out.println(customer1);  
  8.           
  9.         Customer customer2 = session.get(Customer.class, 1l);// 沒有發生SQL語句從一級緩存中獲取數據.  
  10.         System.out.println(customer2);  
  11.           
  12.         System.out.println(customer1 == customer2);// true 一級緩存緩存的是對象的地址.  
  13.         tx.commit();  
  14.         session.close();  
  15.     }  

2.1.3 Hibernate的快照機制詳解:

Hibernate 向一級緩存放入數據時,同時複製一份數據放入到Hibernate快照中,當使用commit()方法提交事務時,同時會清理Session的一級緩存,這時會使用OID判斷一級緩存中的對象和快照中的對象是否一致,如果兩個對象中的屬性發生變化,則執行update語句,將緩存的內容同步到數據庫,並更新快照;如果一致,則不執行update語句。Hibernate快照的作用就是確保一級緩存中的數據和數據庫中的數據一致。

1.1 Hibernate中持久化類的三種狀態說明:

瞭解了主鍵的生成策略之後,我們可以進一步來了解持久化類了。Hibernate爲了更好的來管理持久化類,特將持久化類分成了三種狀態。在Hibernate中持久化的對象可以劃

分爲三種狀態,分別是瞬時態、持久態和脫管態,一個持久化類的實例可能處於三種不同狀態中的某一種,三種狀態的詳細介紹如下。

1、 瞬時態(transient)

瞬時態也稱爲臨時態或者自由態,瞬時態的實例是由new命令創建、開闢內存空間的對象,不存在持久化標識OID(相當於主鍵值),尚未與Hibernate Session關聯,在數據庫中也沒有記錄,失去引用後將被JVM回收。瞬時狀態的對象在內存中是孤立存在的,與數據庫中的數據無任何關聯,僅是一個信息攜帶的載體。

2、 持久態(persistent)

 持久態的對象存在持久化標識OID 加入到了Session緩存中,並且相關聯的Session沒有關閉,在數據庫中有對應的記錄,每條記錄只對應唯一的持久化對象,需要注意的是,持久態對象是在事務還未提交前變成持久態的。

3、 脫管態(detached)

脫管態也稱離線態或者遊離態,當某個持久化狀態的實例與Session的關聯被關閉時就變成了脫管態。脫管態對象存在持久化標識OID,並且仍然與數據庫中的數據存在關聯,只是失去了與當前Session的關聯,脫管狀態對象發生改變時Hibernate不能檢測到。

 學習對象狀態我們要明確的:

a、是爲了更好的掌握hibernate中操作的方法。

b、區分狀態只有兩個標識

一是否有OID

二是否和Session建立的關係

臨時(瞬時)狀態:

沒有OID,和Session沒有關係。

持久化狀態:

有OID,和Session有關係。

脫管狀態:

有OID,和Session沒有關係。

持久化類三種對象狀態的互相轉化

持久化對象的三種狀態可以通過調用Session中的一系列方法實現狀態間的轉換,具體如下: 

1、瞬時態轉換到其他狀態

通過前面學習可知,瞬時態的對象由new關鍵字創建,瞬時態對象轉換到其他狀態總結如下:

1. 瞬時態轉換爲持久態:執行Session的save()或saveOrUpdate()方法。

2.瞬時態轉換爲脫管態:爲瞬時態對象設置持久化標識OID。

由於持久化對象狀態演化圖中沒有涉及到瞬時態轉換到脫管態的情況,這裏做下簡要的說明,在前面學習中可知,脫管態對象存在OID,但是沒有Session的關聯,也就是說脫管態和瞬時態的區別就是OID有沒有值,所以可以通過爲瞬時態對象設置OID,使其變成脫管態對象。

簡言之就是給瞬時態的對象手動賦予一個OID就轉變爲了脫管態

Customer customer = new Customer(); // 瞬時態

customer.setCust_id(1); // 脫管態

2、持久態對象轉換到其他狀態

持久化對象可以直接通過Hibernate 中Session的get()、load()方法,或者Query查詢從數據庫中獲得,持久態對象轉換到其他狀態總結如下:

1.持久態轉換爲瞬時態:執行Session的delete()方法,需要注意的是被刪除的持久化對象,不建議再次使用。

2.持久態轉換爲脫管態:執行Session的evict()、close()或clear()方法。evict ()方法用於清除一級緩存中某一個對象;close()方法用於關閉Session,清除一級緩存;clear()方法用於清除一級緩存的所有對象。

3、脫管態對象轉換到其他狀態

 脫管態對象無法直接獲得,是由其他狀態對象轉換而來的,脫管態對象轉換到其他狀態總結如下:

1.脫管態轉換爲持久態:執行Session的update ()、saveOrUpdate()或lock()方法。

2.脫管態轉換爲瞬時態:將脫管態對象的持久化標識OID設置爲null。

由於持久化對象狀態演化圖中沒有涉及到脫管態轉換到瞬時態的情況,這裏做下簡要的說明,跟瞬時態轉換到脫管態的情況相似,脫管態和瞬時態的區別就是OID有沒有值,所以可以通過將脫管態對象的OID設置爲null,使其變成瞬時態對象。例如在session.close()操作後,加入代碼customer.setCust_id(null);,customer對象將由脫管態轉換爲瞬時態。

 

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