1. 程式人生 > >Hibernate 框架總結

Hibernate 框架總結

Hibernate框架的總結

 

hibernate 簡介:

hibernate是一個開源框架,它是物件關聯關係對映的框架,它對JDBC做了輕量級的封裝,而我們java程式設計師可以使用面向物件的思想來操縱資料庫。

hibernate核心介面

session:負責被持久化物件CRUD操作

sessionFactory:負責初始化hibernate,建立session物件

configuration:負責配置並啟動hibernate,建立SessionFactory

Transaction:負責事物相關的操作

Query和Criteria介面:負責執行各種資料庫查詢

 

Hibernate 核心介面

 

Hibernate的核心介面一共有5個,分別為:Session、SessionFactory、Transaction、Query和Configuration。這5個核心介面在任何開發中都會用到。通過這些介面,不僅可以對持久化物件進行存取,還能夠進行事務控制。

 

·Session介面:Session介面負責執行被持久化物件的CRUD操作(CRUD的任務是完成與資料庫的交流,包含了很多常見的SQL語句。)。但需要注意的是Session物件是非執行緒安全的。

 

·SessionFactory介面:SessionFactroy介面負責初始化Hibernate。它充當資料儲存源的代理,並負責建立Session物件。

 

·Configuration介面:Configuration介面負責配置並啟動Hibernate,建立SessionFactory物件。在Hibernate的啟動的過程中,Configuration類的例項首先定位對映文件位置、讀取配置,然後建立SessionFactory物件。

 

·Transaction介面:Transaction介面負責事務相關的操作。它是可選的,可發人員也可以設計編寫自己的底層事務處理程式碼。

 

·Query和Criteria介面:Query和Criteria介面負責執行各種資料庫查詢。它可以使用HQL語言或SQL語句兩種表達方式。

 

 

hibernate工作原理:

    1.通過Configuration config = new Configuration().configure();//讀取並解析hibernate.cfg.xml配置檔案

    2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>讀取並解析對映資訊

    3.通過SessionFactory sf = config.buildSessionFactory();//建立SessionFactory

    4.Session session = sf.openSession();//開啟Sesssion

    5.Transaction tx = session.beginTransaction();//建立並啟動事務Transation

    6.persistent operate操作資料,持久化操作

    7.tx.commit();//提交事務

    8.關閉Session

    9.關閉SesstionFactory

 

為什麼要用hibernate:

    1. 對JDBC訪問資料庫的程式碼做了封裝,大大簡化了資料訪問層繁瑣的重複性程式碼。

    2. Hibernate是一個基於JDBC的主流持久化框架,是一個優秀的ORM實現。他很大程度的簡化DAO層的編碼工作

    3. hibernate使用Java反射機制,而不是位元組碼增強程式來實現透明性。

    4. hibernate的效能非常好,因為它是個輕量級框架。對映的靈活性很出色。它支援各種關係資料庫,從一對一到多對多的各種複雜關係。

 

Hibernate是如何延遲載入?get與load的區別

    1. 對於Hibernate get方法,Hibernate會確認一下該id對應的資料是否存在,首先在session快取中查詢,然後在二級快取中查詢,還沒有就查詢資料庫,資料 庫中沒有就返回null。

    2. Hibernate load方法載入實體物件的時候,根據對映檔案上類級別的lazy屬性的配置(預設為true),分情況討論:

        (1)若為true,則首先在Session快取中查詢,看看該id對應的物件是否存在,不存在則使用延遲載入,返回實體的代理類物件(該代理類為實體類的子類,由CGLIB動態生成)。等到具體使用該物件(除獲取OID以外)的時候,再查詢二級快取和資料庫,若仍沒發現符合條件的記錄,則會丟擲一個ObjectNotFoundException。

        (2)若為false,就跟Hibernateget方法查詢順序一樣,只是最終若沒發現符合條件的記錄,則會丟擲一個ObjectNotFoundException。

 

get和load有兩個重要區別:

    如果未能發現符合條件的記錄,Hibernate get方法返回null,而load方法會丟擲一個ObjectNotFoundException。

    load方法可返回沒有載入實體資料的代 理類例項,而get方法永遠返回有實體資料的物件。

    總之對於get和load的根本區別,一句話,hibernate對於 load方法認為該資料在資料庫中一定存在,可以放心的使用代理來延遲載入,如果在使用過程中發現了問題,只能拋異常;而對於get方 法,hibernate一定要獲取到真實的資料,否則返回null。

 

Hibernate中怎樣實現類之間的關係?(如:一對多、多對多的關係)

    類與類之間的關係主要體現在表與表之間的關係進行操作,它們都是對物件進行操作,我們程式中把所有的表與類都對映在一起,它們通過配置檔案中的many-to-one、one-to-many、many-to-many、

 

陣列對映:<array />    有序,通過下標訪問

            <key />    對映集合屬性資料表的外來鍵列

            <list-index />    用於對映陣列的下標列,用於儲存陣列的下標值

            <element />    對映儲存集合元素

 

List 集合對映:<list />    有序,通過下標訪問

            <key />    對映集合屬性資料表的外來鍵列

            <list-index />    對映集合屬性資料表的集合索引列

            <element />    對映儲存集合元素的資料列,需要指定 type

 

Set 集合對映:<set /> 無序,唯一,不可重複

            <key />    對映集合屬性資料表的外來鍵列

            <element />    對映儲存集合元素的資料列,需要指定 type

 

Map 集合對映: <map /> key 是無序的,唯一的,value 是無序的,不唯一的

            <key />    對映集合屬性資料表的外來鍵列

            <map-key />    對映 Map 集合的 key 值,需要指定 type

            <element />    對映儲存集合元素的資料列,需要指定 type

 

Hibernate 中的關係對映

    主鍵雙向一對一關聯: 兩個表中的主鍵共享一個值,從表中的主鍵是從主表中獲取得到

        在主表對映檔案中配置:

            設定主鍵生成策略:在<id>中配置

                <generator    class="foreign">

                        <param    name="property>引用的主表中的從表自定義屬性名</param>

                </generator>

            

            <one-to-one    name="主表中的從表自定義屬性名"    constrained="true"    />

 

        在從表對映檔案中配置:

            <one-to-one    name="從表中的主表自定義屬性名">

    

    外來鍵雙向一對一關聯: 通過外來鍵方式引用主表中的主鍵,並且設定外來鍵屬性為唯一屬性

        在主表對映檔案中配置:

            <one-to-one    name="主表中的從表自定義屬性名"    property-ref="從表中的主表自定義屬性名"    cascade="all" />

        

        在從表對映檔案中配置:

            <many-to-one    name="從表中主表自定義屬性名"    column="外來鍵列名"    unique="true" />

 

    雙向一對多關聯:(以 set 為例,其餘集合同配置)

        在主表對映檔案中配置:

            <set    name="主表中從表自定義屬性名"    inverse="true">

                <key    column="外來鍵列名" />

                <one-to-many    class="從表屬性類路徑">

            </set>

 

        在從表對映檔案中配置:

            <many-to-one    name="從表中主表自定義屬性名"    column="外來鍵列名"    class="主表屬性類路徑"    cascade="all" />

 

    雙向多對多關聯:(以 set 為例)

        在主表對映檔案中配置:

            <set    name="主表中從表自定義屬性名"    table="中間表名"    cascade="all">

                <key    column="主表在中間表的外來鍵名">

                <many-to-many    class="從表屬性類路徑"    column="從表在中間表的外來鍵名" />

            </set>

 

        在從表對映檔案中配置:

            <set    name="從表中主表自定義屬性名"    table="中間表名"    inverse="true">

                <key    column="從表在中間表的外來鍵名">

                <many-to-many    class="主表屬性類路徑"    column="主表在中間表的外來鍵名" />

            </set>

 

Hibernate的查詢方式Sql、Criteria,object comptosition

Hql:

1、 屬性查詢

2、 引數查詢、命名引數查詢

3、 關聯查詢

4、 分頁查詢

5、 統計函式

 

過濾器與攔截器

    使用過濾器的步驟:

        ① 定義過濾器,使用 <filter-def />定義過濾器(mapping的子元素)

        ② 使用過濾器,使用 <filter /> 應用過濾器(class的子元素)

        ③ 程式碼中通過 session 啟用過濾器

            session.enableFilter("過濾器名").setParameter("過濾器屬性名","值");

    過濾器類似於集合上的 where 屬性條件

    當某個查詢條件使用的非常頻繁的時候,那麼就可以將條件設定為過濾器。

 

    攔截器:① 實現 Interceptor 介面,重寫所有方法

                 ② 繼承 EmptyInterceptor 類(推薦使用)

    常用方法:

        onLoad: 載入持久化實體時呼叫

        onSave: 儲存資料的時候呼叫,資料還沒有儲存到資料庫

        onFlushDirty: 更新資料時呼叫,但資料還沒有更新到資料庫

        onDelete: 當刪除實體時呼叫

        preFlush:持久化所做修改之前呼叫

        postFlush: 持久化所做修改之後呼叫

    攔截器的配置:

        ① 全域性攔截器配置

                Configuration cfg = new Configuration().configure();

                cfg.setInterceptor(配置的攔截器類);

        ② 區域性攔截器配置

                session = factory.withOptions().interceptor(配置的攔截器類).openSession();

 

如何優化Hibernate?

    1.使用雙向一對多關聯,不使用單向一對多

    2.靈活使用單向一對多關聯

    3.不用一對一,用多對一取代

    4.配置物件快取,不使用集合快取

    5.一對多集合使用Bag,多對多集合使用Set

    6. 繼承類使用顯式多型

    7. 表字段要少,表關聯不要怕多,有二級快取撐腰

 

hibernate的開發步驟:開發步驟

    1)搭建好環境

        引入hibernate最小的jar包

        準備Hibernate.cfg.xml啟動配置檔案

    2)寫實體類(pojo)

    3)為實體類寫對映檔案"User.hbm.xml"

        在hibernate.cfg.xml新增對映的實體

    4)建立庫表

    5)寫測試類

        獲得Configuration

        建立SessionFactory

        開啟Session

        開啟事務

        使用session操作資料

        提交事務

        關閉資源

 

Hibernate 註解

    注:GeneratedValue指定了識別符號的生成策略。jpa提供了4種標準用法。

    01.AUTO:根據不同的資料庫選擇不同的策略

    02.TABLE:使用表儲存id值

    03.INDENITY:使用資料庫自動生成主鍵

    04.SEQUENCE:使用序列建立主鍵(如Oracle)

雙向外來鍵一對一:@OneToOne

    在主表類中 從表屬性上配置:

        @OneToOne(cascade=CascadeType.ALL)

        @JoinColumn(name="新增的外來鍵名",unique=true)

    在從表類中 主表屬性上配置:

        @OneToOne(mappedBy="主表中從表的自定義屬性名")

    注:雙向關聯,必須設定 mappedBy 屬性 ,因為雙向關聯只能交給一方去維護,不能在兩邊都設定外來鍵關聯,否則雙方都無法儲存。

 

雙向主鍵一對一

    在主表類中 

        主表主鍵上配置:

            @Id

            @GeneratedValue(generator="策略名")

            @GenericGenerator(name="策略名",strategy="assigned")    //設定為手動輸入 方便測試

        在主表中從表自定義屬性上配置:

            @OneToOne(cascade=CascadeType.ALL)

            @PrimaryKeyJoinColumn

    

    在從表類中 

        從表主鍵上配置:

            @Id

            @GeneratedValue(generator="策略名")

            @GenericGenerator(name="策略名",strategy="foreign",parameters={@Parameter(name="property",value="從表中主表自定義屬性名")})

        在從表中主表自定義屬性上配置:

            @OneToOne(mappedBy="主表中從表自定義屬性名")

 

雙向一對多

    在主表中從表自定義屬性上配置:

            @ManyToOne

            @JoinColumn(name="外來鍵名",referencedColumnName="從表中關聯的id")

    

    在從表中主表自定義屬性上配置:

            @OneToMany(mappedBy="主表中從表自定義屬性名",cascade=CascadeType.ALL)

 

雙向多對多

    在主表中從表自定義屬性上配置:

            @ManyToMany(cascade=CascadeType.ALL)

            @JoinTable (

                    name="中間表名",

                    joinColumns={@JoinColumn(name="主表在中間表的id")},

                    inverseJoinColumns={@JoinColumn(name="從表在中間表的id")}

             )

 

    在從表中主表自定義屬性上配置:

            @ManyToMany(mappedBy="主表中從表自定義屬性名")

 

注意:在判斷到底是誰維護關聯關係時,可以通過檢視外來鍵,哪個實體類定義了外來鍵,哪個類就負責維護關聯關係。

 

Hibernate快取的作用:

    Hibernate是一個持久層框架,經常訪問物理資料庫,為了降低應用程式對物理資料來源訪問的頻次,從而提高應用程式的執行效能。快取內的資料是對物理資料來源中的資料的複製,應用程式在執行時從快取讀寫資料,在特定的時刻或事件會同步快取和物理資料來源的資料

 

Hibernate快取分類:

    Hibernate快取包括兩大類:Hibernate一級快取和Hibernate二級快取

       Hibernate一級快取又稱為“Session的快取”,它是內建的,意思就是說,只要你使用hibernate就必須使用session快取。由於Session物件的生命週期通常對應一個數據庫事務或者一個應用事務,因此它的快取是事務範圍的快取。在第一級快取中,持久化類的每個例項都具有唯一的OID。

 

       Hibernate二級快取又稱為“SessionFactory的快取”,由於SessionFactory物件的生命週期和應用程式的整個過程對應,因此Hibernate二級快取是程序範圍或者叢集範圍的快取,有可能出現併發問題,因此需要採用適當的併發訪問策略,該策略為被快取的資料提供了事務隔離級別。第二級快取是可選的,是一個可配置的外掛,在預設情況下,SessionFactory不會啟用這個外掛。

 

什麼樣的資料適合存放到第二級快取中?   

    1 很少被修改的資料   

    2 不是很重要的資料,允許出現偶爾併發的資料   

    3 不會被併發訪問的資料   

    4 常量資料  

 

不適合存放到第二級快取的資料?   

    1經常被修改的資料   

    2 .絕對不允許出現併發訪問的資料,如財務資料,絕對不允許出現併發   

    3 與其他應用共享的資料。

 

Hibernate查詢物件如何應用快取?

    當Hibernate根據ID訪問資料物件的時候,首先從Session一級快取中查;查不到,如果配置了二級快取,那麼從二級快取中查;如果都查不到,再查詢資料庫,把結果按照ID放入到快取

    刪除、更新、增加資料的時候,同時更新快取

 

Hibernate管理快取例項無論何時,我們在管理Hibernate快取(Managing the caches)時,當你給save()、update()或saveOrUpdate()方法傳遞一個物件時,或使用load()、 get()、list()、iterate() 或scroll()方法獲得一個物件時, 該物件都將被加入到Session的內部快取中。

當隨後flush()方法被呼叫時,物件的狀態會和資料庫取得同步。 如果你不希望此同步操作發生,或者你正處理大量物件、需要對有效管理記憶體時,你可以呼叫evict() 方法,從一級快取中去掉這些物件及其集合。