Hibernate知識點複習之二

Hibernate學習之二

一 Hibernate持久化類

1 什麼是持久化類?
    Hibernate是持久層ORM映射框架, 專注於數據的持久化 ,所謂的持久化 就是將內存中的數據永久存儲到關係型數據庫的過程。
      而持久化類就是 通過映射文件與數據庫建立起映射關係的Java類。
2 持久化類的編寫規則:
       1. 需提供無參構造方法。(Hibernate底層是通過反射技術生成持久類的實例)
       2. 類屬性需私有化, 提供私有的getter和setter方法。(Hibernate底層將查詢到數據通過get/set方法進行封裝處理)
       3.類屬性類型使用包裝類。(包裝類的語義描述更清晰,如:Integer中 null 和 0 代表兩種情況,而這兩種情況 int 只能使用 0 來表示)
       4.持久化類要有一個唯一標識(oid)與表主鍵對應。(Hibernate需通過此唯一標識oid來區分內存中是否是同一個持久化對象,Hibernate不允許存在同oid的兩個持久化對象)
      5.持久化類儘量不使用final修飾。(Hibernate的延遲加載機制 是通過字節碼增強技術來產生一個代理對象,通過產生當前類的一個子類對象實現,
                                                      若final修飾,不能產生子類,也就不能產生代理對象, Hibernate的延遲加載策略(一種優化手段)就會失效。
3 Hibernate的主鍵生成策略
    1.主鍵類型
            #自然主鍵:把具業務含義的字段作爲主鍵,如customer表中的 name作主鍵
            #代理主鍵:把不具業務含義的字段作爲主鍵,該字段一般取名爲id,通常爲整數類型(比字符串類型節省更多空間)
    2.主鍵生成策略 <generator class="主鍵生成策略屬性"></generator>
            #assigned:自然主鍵策略,需開發人員手動錄入指定主鍵,若id不指定generator屬性,Hibernate默認使用這種主鍵生成策略。
            #increment:代理主鍵策略,整型數據主鍵自增,增量爲1,存在線程安全問題,不適用多線程操作同一張表的情況,不能在集羣環境下使用
            #uuid:代理主鍵策略,產生隨機字符串作爲主鍵,主鍵類型必須爲String ,Hibernate採用128位的UUID算法來生成(長度爲32位十六進制的)唯一的字符串標識符
            #identity:代理主鍵策略,採用底層數據庫本身提供的主鍵生成標識符,該生成器要求數據庫中把主鍵定義爲自增長類型
            #sequence:代理主鍵策略,根據底層數據庫序列生成標識符,該數據庫需支持序列(Oracle的主鍵生成策略)
            #native:代理主鍵策略,根據底層數據庫 自動生成標識符能力來選中 identity,sequence,hilo(高低算法生成器) 三種生成器中的一種,適合跨數據庫平臺開發
4 Hibernate的持久化對象的三種狀態
    1 概述:Hibernate爲了更好管理持久化類,特將持久化類分三種狀態:瞬時態,持久態,託管態
    2 瞬時態(transient):不存在持久化標識oid,尚未與Hibernate的Session關聯的持久化對象。
                    細述:瞬時態也稱臨時態或自由態,瞬時態的實例由new 命令創建,在內存開闢空間的孤立對象,與數據庫無關聯。
    3 持久態(persistent):存在持久化標識oid,加入到Session緩存中,且相關聯的Session沒有關閉(執行close()方法),持久化狀態對象的任何變化都會自動同步到數據庫中
                    如:存在持久態對象c,執行方法c.setCust_name("微軟公司")後  不需調用Session.update(c) 即可自動把數據更新到數據庫中
                    細述:值得一提的是,持久化對象是在事務提交前變成持久態的。Session.save()方法就是 瞬時態 轉換爲 持久態的 過程                     
    4. 託管態(detached):失去Session關聯,仍然存在oid,與數據庫存在關聯
                    細述:託管態也稱遊離態或離線態,當某個持久化狀態的對象與Session關聯被關閉了就會變成託管態,託管態對象發生改變時Hibernate不能檢測到
                              Session.close()方法就是 持久態 轉換爲 託管態的過程
    5. 三種狀態相互轉換
                #瞬時態
                        *轉 持久態:save()或saveOupdate
                        *轉 託管態:爲瞬時態對象設置oid
                #持久態
                        *轉 瞬時態:delete()
                        *轉 託管態:close()
                #託管態
                        *轉 瞬時態:將對象的oid設爲null
                        *轉 持久態:update()或 saveOrUpdate()

二 Hibernate的一級緩存

    @概述:持久化對象可以自動更新數據庫依賴於Hibernate的一級緩存
    @什麼是Hibernate的一級緩存?
                #緩存概念:緩存介於應用程序和永久性數據存儲源(硬盤,數據庫)之間,其作用是降低應用程序直接讀取永久性數據存儲源的頻率,從而提高應用的運行性能
                                  緩存中的數據是永久性數據存儲源中數據的拷貝,它的物理介質通常是內存
                #Hibernate緩存:Hibernate緩存分爲一級緩存和二級緩存,Hibernate這兩級緩存都位於持久層,存儲的都是數據庫備份數據,
                                           其中Hibernate一級緩存爲內置緩存,不能被卸載
                #Hibernate一級緩存:
                                    *概念:Hibernate的一級緩存就是指Session緩存(一塊內存空間),用來存放相互管理的java對象。Session接口的實現包含了一系列的Java集合,這些java集合
                                            構成了Session緩存,只要Session實例沒有結束生命週期,存放在它緩存中的對象就不會結束生命週期,因此一級緩存也被稱爲是Session基本的緩存
                                    *持久化對象自動更新數據庫的原理:
                                            在使用Hibernate查詢對象時,會先使用對象的oid屬性在Hibernate的一級緩存中(Session緩存)進行查找,如果找到匹配oid值的對象,
                                            則直接從一級緩存中取出,不會再查詢數據庫。若沒有找到匹配oid值的對象,則去數據庫中查找相應的數據,從數據庫中查詢到的數據也會
                                            放進一級緩存中。
                                    *Hibernate的一級緩存作用:減少對數據庫訪問的次數
                                    *Hibernate一級緩存的特點:
                                            &當應用程序調用Session接口的save(),update(),saveOrUpdate(),如果Session緩存中沒有相應的對象,Hibernate就會自動進入數據庫查詢,
                                               將查詢到相應的對象信息加入到一級緩存中
                                            &當調用Session接口的load(),get()方法,以及Query接口的 list(),iterator() 方法時,先判斷Session緩存中有無對象,有則返回,沒有則
                                                數據庫查詢,並將查詢結果存進Session緩存中。
                                            &當調用Session的close()方法,Session緩存會被清空。
                                    *Hibernate一級緩存是否存在示例:
                                           //第一次獲取id爲1的Customer對象,Session緩存中沒有,會進行數據庫查詢操作,打印出sql查詢語句,並存進Session緩存中
                                            Customer c1 = session.get(Customer.class,1L);
                                            System.out.println(c1);
                                            System.out.println("---------------------------------------");
                                            //第二次獲取同一個id爲1的Customer對象,此時其已存在Session緩存中,不會進行數據庫查詢操作,不會打印出sql查詢語句
                                            Customer c2=session.get(Customer.class,1L);
                                            System.out.println(c2);
                                            System.out.println(c1==c2); //返回true,獲取的是同一個對象
                                    *Hibernate一級緩存的快照:
                                            &概述:一級緩存之所以可以更新數據庫,依賴於一級緩存中的快照區域
                                            &底層原理:Hibernate向一級緩存存數據時,同時會拷貝一份到一級緩存中的快照區裏。當執行事務提交commit()方法時,Hibernate會
                                                            比對一級緩存中的數據和內部的快照區數據是否一致,若不一致則底層自動update操作,把新數據同步更新到數據庫中,
                                                            若一致則不更新。
                                            &作用:確保一級緩存中 的數據與數據庫的一致
                                    *Hibernate一級緩存和一級緩存中的快照區職能總結:
                                            &一級緩存主要應用於 Session進行CRUD中查取操作時,減少對數據庫的訪問  (查取操作)
                                            &快照區則爲了保證 一級緩存區的數據與數據庫一致,而對數據庫進行數據更新 (更新操作)

三 Hibernate的事務控制

1. 什麼是事務?
    #概述:在數據庫操作中,一項事務是由一條或多條操作數據庫的sql語句組成的不可分割的工作單元。當事務中所有sql操作都正常時,整個事務纔可被提交到數據庫中,
      若有一項操作沒有完成,則整個事務會被回滾。
    #歸納理解:事務可以理解爲邏輯上的一組操作,組成這組操作的各個單元,要麼一起成功,要麼一起失敗
    #事務的ACID特性:
            &原子性(Atomic):將事務中所有操作捆綁成一個不可分割的單元,不可分割在於,事務的所有操作要麼全部執行要麼全部不執行
            &一致性(Consistency):事務完成後,所有數據都保持一致狀態
            &隔離性(Isolation):一個事務的執行不能被其他事務干擾。即一個事務的操作及使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。
            &持久性(Durablility):也稱永久性,指一個事務一旦提交,它對數據庫中數據的改變是永久性的,完成提交後,產生的其他操作或故障不會對其影響。
2. 事務中的併發問題:
    #概述:實際開發中,數據庫是要被多個用戶訪問的。多個事務訪問同一個數據庫時會發生併發問題。
    #事務併發產生的問題:
        & 髒讀(Dirty Read):一個事務讀取到另一個事務中未提交的數據
                    如:事務T1修改了一行數據,但是還沒有提交,這時候事務T2讀取了被事務T1修改後的數據,
                           之後事務T1因爲某種原因Rollback了,那麼事務T2讀取的數據就是髒的
        & 不可重複讀(None-Repeatable Read):一個事務中兩次讀同一行數據,可兩次讀到的數據內容不一致
                    如:事務T1讀取某一數據,事務T2讀取並修改(update)了該數據,T1爲了對讀取值進行檢驗而再次讀取該數據,便得到了不同的結果。
        & 虛讀/幻讀:事務在操作過程中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的數據或者缺少了第一次查詢中出現的數據
                     如:事務T1在查詢某數據庫的數據時,T2在該數據庫插入(insert)或刪除(delete)了一條記錄,事務T1查完第一次,想確認查詢第二遍時發現前後數據數量不一致。
        & 更新丟失(Update Lost):兩個事務都同時更新(update)一行數據,但是第二個事務卻中途失敗退出,導致對數據的兩個修改都失效了。
                     這是因爲系統沒有執行任何的鎖操作,因此併發事務並沒有被隔離開來。
    #爲解決事務併發問題而定義的4個事務隔離級別:
        &讀未提交(Read Uncommitted,1級):
             一個事務可以訪問另一個事務未成功提交的修改(update)和插入(insert)數據,但當一個事務在寫數據時,另一個事務不可也進行寫操作,只允許讀此行數據。
             讀事務不阻塞其他讀事務和寫事務,未提交的寫事務阻塞其他寫事務但不阻塞讀事務。
            此隔離級別可以防止更新丟失,但不能防止髒讀、不可重複讀、幻讀。
        & 讀已提交(Read Committed,2級,oracle默認的):
             一個事務可以訪問另一個事務成功提交的修改(update)和插入(insert)數據,但未提交的寫事務,禁止其他事務訪問該行。
             讀事務允許其他讀事務和寫事務,未提交的正在進行的寫事務禁止其他讀事務和寫事務
            此隔離級別可以防止更新丟失、髒讀,但不能防止不可重複讀、幻讀。
        & 可重複讀(Repeatable Read,4級,mysql默認的):
            以操作同一行數據爲前提,讀事務禁止其他寫事務但不阻塞讀事務,未提交的寫事務禁止其他讀事務和寫事務。
            此隔離級別可以防止更新丟失、髒讀、不可重複讀,但不能防止幻讀
        & 序列化/串行化(Serializable,8級):
            提供嚴格的事務隔離,它要求事務序列化執行,事務只能一個接着一個地執行,不能併發執行。(相當於鎖表,性能差沒人用)
            此隔離級別可以防止更新丟失、髒讀、不可重複讀、幻讀。
        & 總結:隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響也越大。對於多數應用程序,
                    可以優先考慮把數據庫系統的隔離級別設爲Read Committed。它能夠避免更新丟失、髒讀,而且具有較好的併發性能。
                    儘管它會導致不可重複讀、幻讀這些併發問題,在可能出現這類問題的個別場合,可以由應用程序採用悲觀鎖或樂觀鎖來控制。
        & 配置文件對事務中隔離級別進行配置:
                    隔離級別爲:
                    0001 1    第一級別(讀未提交)
                    0010 2    第二級別(讀已提交)
                    0100 4    第三級別(讀可重複)(mysql數據庫爲4)
                    1000 8    第四級別(串行化)
                    <property name="hibernate.connection.isolation">4</property>

四 Hibernate的事務管理

1. 如何保證在Service層開啓事務時使用的Session對象,與在dao層進行多個操作時使用的是同一個Session對象?
    # 在業務層獲取到Session後,將Session作爲參數傳遞給DAO
    # 使用ThreadLocal將業務層獲取到Session綁定到當前線程中,從而,dao層獲取的Session都是從當前線程。具體實現Hibernate幫助我們完成,只需進行配置
        & Hibernate提供三種管理Session對象的方法:
            1 Session對象的生命週期與本地線程綁定(這是調用sessionFactory.getCurrentSession()方法,獲取與當前線程綁定Session必備的配置)
                <property name="hibernate.current_session_context_class">thread</property>
            2 Session對象的生命週期與JTA事務綁定
                <property name="hibernate.current_session_context_class">jta</property>
            3 Hibernate委託程序來管理Session對象的生命週期
                <property name="hibernate.current_session_context_class">managed</property>

五 Hibernate的Query對象

1 Query對象(代表面向對象的一個Hibernate查詢操作)
    概述:在Hibernate中,通常使用session.createQuery()方法接收一個hql語句,獲取一個Query對象,然後調用Query對象的list()或uniqueResult()方法進行查詢,
              hql(Hibernate Query Language)語句,語法很像sql,但它是全面向對象的,如果HQL語句含有參數,則可調用Query的setXxx()設置參數
2 Query對象的常用API查詢示例:
    # 基本查詢:
        String hql="from Customer";   //書寫hql語句
        Query query = session.createQuery(hql);  //創建查詢對象
        List<Customer> list = query.list(); //執行查詢
    #條件查詢:
        String hql="from Customer where cust_id = 1L";  //書寫hql語句
        Query query = session.createQuery(hql);  //創建查詢對象
        Customer uniqueResult = (Customer) query.uniqueResult();//執行查詢
     #佔位符?的使用
          String hql="from Customer where cust_id = ?"; //書寫hql語句
         Query query = session.createQuery(hql);  //創建查詢對象
         //query.setLong(0, 1L);
         query.setParameter(0,1L);//此方法會自動幫你轉化處於佔位符中的數據類型
         Customer uniqueResult = (Customer) query.uniqueResult();//執行查詢
    #命名佔位符 =: 的使用
            String hql="from Customer where cust_id=:myId"; //書寫hql語句--設置命名佔位符
            Query query = session.createQuery(hql);  //創建Query對象
            query.setParameter("myId",1L);  //爲命名佔位符設置參數
            Customer uniqueResult = (Customer) query.uniqueResult();  //執行查詢
    # 分頁查詢:
            String hql="from Customer";
            Query query = session.createQuery(hql);
            //limit 0,5
            query.setFirstResult(0); //從0條記錄開始查詢
            query.setMaxResults(5); //查詢到第5條
            List<Customer> list = query.list();
3 Query的其他API
    # setter方法(如:setParameter("","");setLong("",""))
        提供一系列的setter方法針對不同數據類型設置 查詢參數
    #iterator()
        該方法用於查詢語句,迭代讀取時按照順序讀取,把使用到數據轉換到java對象
    # executeUpdate()
        Hbernate3 新特性,它支持hql的更新和刪除操作

六 Hibernate的Criteria對象

1 概述:
    Criteria是一個完全不需考慮數據庫底層實現,sql的編寫,完全面向對象,可擴展的條件查詢API.它是Hibernate框架的核心查詢對象。
    Criteria查詢 也稱QBC(Query By Criteria )查詢,它是Hibernate的一種對象檢索方式。
2 org.hibernate.criterion接口:
    Criterion是Hibernate一個提供面向對象查詢條件的 接口,Cirterion接口的一個實例就是一個單獨的查詢條件,而Criterion實例是由工廠類Restrictions的靜態方法完成。
    Criteria對象需通過add()方法添加Criterion實例查詢條件,從而創建查詢。
3 Criteria條件查詢sql操作符對應的方法:
     * >                    gt()
     * >=                   ge()
     * <                        lt()
     * <=                       le()
     * ==                   eq()
     * !=                       ne()
     * in                       in()
     * between and      between()
     * like                     like()
     * is not null          isNotNull()
     * is null              isNull()
     * or                   or()
     * and                  and()
4 Criteria的QBC查詢API:
      #基本查詢
            //創建Criteria對象
            Criteria criteria = session.createCriteria(Customer.class);
            //執行QBC查詢
            List<Customer> list = criteria.list();
      #條件查詢
            //創建查詢  
            Criteria criteria = session.createCriteria(Customer.class);
            //設置查詢條件
            criteria.add(Restrictions.eq("cust_id",1L));
            //執行查詢
            Customer c = (Customer) criteria.uniqueResult();
      #分頁查詢
            //創建查詢對象
            Criteria criteria = s.createCriteria(Customer.class);
            //設置查詢條件
            criteria.setFirstResult(0);
            criteria.setMaxResults(5);
            //執行查詢
            List<Customer> list = criteria.list();
      #查詢總記錄
            //創建查詢對象
            Criteria criteria = s.createCriteria(Customer.class);
            //設置查詢條件
            criteria.setProjection(Projections.rowCount());
            //執行查詢
            Long uniqueResult = (Long) criteria.uniqueResult();

七 Hibernate的SQLCriteria對象

1 概述:SQLCriteria接口用於接收sql原生語句進行查詢,然後調用list()或 uniqueResult()方法獲取結果
             但sql語句不會手動封裝到實體,需要我們手動調用 addEnity()進行封裝
2 SQLCirteria查詢示例:
        //書寫原生sql語句
        String sql="select * from cst_customer";
        //創建查詢對象
        SQLQuery sqlQuery = s.createSQLQuery(sql);
        //3 獲取查詢結果
        //沒使用手動封裝實體的方式:
        /*List<Object[]> list = sqlQuery.list();
        for(Object[]objs:list) {
            System.out.println(Arrays.toString(objs));
        }*/
        //使用手動封裝實體方式:
        sqlQuery.addEntity(Customer.class);
        //執行查詢
        List<Customer> list = sqlQuery.list();

八 Hibernate的Query,Criteria,SQlCriteria三大API對象總結:

Query對象:書寫的是hql語句,然後放進  session.createQuery(hql)方法創建查詢對象,由setter方法設置查詢條件,list()和uniqueResult()執行查詢獲取結果
Criteria對象:不需書寫hql語句,使用 session.createCriteria(xxx.class)關聯對應實體,由QBC查詢方法設置查詢條件,list()和uniqueResult()執行查詢獲取結果
SQLQuery對象:書寫的是原生sql語句,使用 session.createSQLQuery(sql)創建查詢對象,addEnity(xxx.class)封裝實體,list()和uniqueResult()執行查詢獲取結果
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章