posts - 78, comments - 34, trackbacks - 0, articles - 1
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

                   從昨晚后半夜開(kāi)始下午,現(xiàn)在外面的雪還沒(méi)停,這是來(lái)北京后最大的一場(chǎng)雪。早上630起床,然后去吃早餐。今天是元旦假期的最后一天,幸好乘車(chē)的人不多,很快就坐上了車(chē)。如果是平時(shí)可能得在大雪里走幾站,甚至走到學(xué)校。氣溫還可以,在外面等車(chē)時(shí),雪好美!

           

          今日繼續(xù)講解hibernate,也是hibernate課程的最后一天。Hibernate的內(nèi)容非常多,如果詳細(xì)著講估計(jì)還得兩天,但課程安排是三天。大部分之前的學(xué)生說(shuō)外面用hibernate的很少!~~ 無(wú)奈!繼續(xù)上一次課程

           

          一、Hibernate的檢索策略

                   上一次課程我們學(xué)習(xí)了類(lèi)級(jí)別的檢索策略和關(guān)聯(lián)級(jí)別的一對(duì)多檢索策略,簡(jiǎn)單復(fù)習(xí)一下:

          一對(duì)多關(guān)聯(lián)檢索:

          Fecth            lazy

          True

          false

          extra

          Join

          迫左

          迫左

          迫左

          Select

          延遲

          立即

          延遲(特別)

          subselect

           

           

           

           

          Fecth的優(yōu)先級(jí)別高于lazy

          延遲(特別):select count(id) from orders where cid=?

          Subselect:使用嵌套子查詢,批量查詢的時(shí)候。

           

          多對(duì)一關(guān)聯(lián)檢索:

          Fecth            lazy

          false

          proxy

          No-proxy

          Join

          迫左

          迫左

          迫左

          Select

          立即

          延遲:對(duì)端類(lèi)級(jí)別是延遲

          立即:對(duì)端類(lèi)級(jí)別是立即

           

          表單所屬的客戶,客戶是表單的一級(jí)關(guān)聯(lián),再取出客戶對(duì)應(yīng)的所有表單,此時(shí)表單是前一個(gè)表單的二級(jí)關(guān)聯(lián)。一級(jí)關(guān)聯(lián)、二級(jí)關(guān)聯(lián),兩次左外連接使用一條語(yǔ)句的話,會(huì)降低性能。所以使用了一條左邊連接查詢和一條查詢語(yǔ)句。這就是著名的N+1查詢。

          hibernate3.0的所有檢索策略都為延遲

           

          接下來(lái)我們繼續(xù)學(xué)習(xí)關(guān)聯(lián)級(jí)別的一對(duì)一檢索策略與多對(duì)多檢索策略。

           

          1.一對(duì)一檢索策略

                   一對(duì)一關(guān)聯(lián)關(guān)系是一種什么樣的關(guān)系?一對(duì)一關(guān)系不可以把他們定義為一個(gè)類(lèi)嗎?把他們放在一個(gè)表里不可以嗎?當(dāng)然可以!

           

                   一對(duì)一關(guān)聯(lián)兩種方案:

          1).外鍵關(guān)聯(lián),此種解決方案有兩種方法:

          老徐舉的例子,一個(gè)用戶表對(duì)應(yīng)一個(gè)地址。為什么要這么做?假設(shè)地址中包含大字段,這樣可以減少資源的浪費(fèi),提高訪問(wèn)性能。

          l          方法一、就是在多對(duì)一關(guān)聯(lián)的元素節(jié)點(diǎn)中添加一個(gè)unique=”true”屬性便形成了一對(duì)一關(guān)聯(lián)。

          在用戶類(lèi)的映射文件中添加:

          <!-- 影射一對(duì)一外鍵關(guān)聯(lián)用many-to-one進(jìn)行模擬,增加唯一性約束 -->

          <many-to-one name="addr" column="aid" class="AddrFk" unique="true" />

          在地址類(lèi)的映射文件中添加:

          <one-to-one name="user" property-ref="addr"/>

          l          方法二、直接使用一對(duì)一關(guān)系:

          在用戶類(lèi)的映射文件中添加:

          <!-- 影射一對(duì)一主鍵關(guān)聯(lián) -->

          <one-to-one name="addr" class="AddrPk" />

          在地址類(lèi)的映射文件中添加:

          <one-to-one name="user" class="UserPk" constrained="true"/>

                             同時(shí)我們需要設(shè)置地址類(lèi)映射文件的主鍵為:

          <id name="id" column="id" type="integer">

              <generator class="foreign">

                 <param name="property">user</param>

              </generator>

          </id>

                   將用戶表的主鍵設(shè)置為地址表的外鍵。

           

          2).主鍵關(guān)聯(lián),此時(shí)子表的主鍵與主表的主鍵一一對(duì)應(yīng)。有三種解決方案:

          老徐舉了一個(gè)例子:?jiǎn)T工有鐘點(diǎn)工和普通工人之分,鐘點(diǎn)工領(lǐng)取的是時(shí)效工資(rate),普通工人領(lǐng)取的是月薪(salary)。所以我們有必要提取一個(gè)員工的超類(lèi),并分別實(shí)現(xiàn)鐘點(diǎn)工和普通工人的子類(lèi)。

          l          方法一、我們將鐘點(diǎn)工和普通工人的信息放到一個(gè)表里,需要在映射文件中添加:

          <!-- 區(qū)分符 -->

          <discriminator column="etype" type="string" length="2" />

          <property name="name" column="name" type="string" length="15" />

          <!-- 子類(lèi)(整個(gè)繼承關(guān)系樹(shù)對(duì)應(yīng)于一個(gè)表) -->

          <subclass name="HeSingle" discriminator-value="he" lazy="false">

              <property name="rate" column="rate" type="float" />

          </subclass>

          <subclass name="SeSingle" discriminator-value="se" lazy="false">

              <property name="salary" column="salary" type="float" />

          </subclass>

          注意“discriminator”元素用于定義一個(gè)額外的列,用于區(qū)分員工的類(lèi)型。

          l          方法二、我們?yōu)槊款?lèi)員工都分別建一個(gè)表,如:

          <!-- 每個(gè)子類(lèi)對(duì)應(yīng)一個(gè)表,從表和主表間一對(duì)一關(guān)系 -->

          <joined-subclass name="HeJoined" table="hib_hejoineds" lazy="false">

              <key column="eid" />

             <property name="rate" column="rate" type="float" />

          </joined-subclass>

                

          <joined-subclass name="SeJoined" table="hib_sejoineds" lazy="false">

              <key column="eid" />

              <property name="salary" column="salary" type="float" />

          </joined-subclass>

          column="eid"”被做為外鍵對(duì)應(yīng)主表的員工id

          l          方法三、為每類(lèi)員工建立一個(gè)表,他們與主表無(wú)關(guān)各自具有全字段。但是這三個(gè)表所使用的Id是不重復(fù)的:

          <union-subclass name="HeUnion" table="hib_heunions">

              <property name="rate" column="rate" type="float" />

          </union-subclass>

          <union-subclass name="SeUnion" table="hib_seunions">

              <property name="salary" column="salary" type="float" />

          </union-subclass>

                             此時(shí),我們需要使用一個(gè)特殊的主鍵增值生成器:

          <id name="id" column="id" type="integer">

              <generator class="hilo">

                 <param name="table">hib_hilo</param>

                 <param name="column">currvalue</param>

                 <param name="max_lo">10</param>

              </generator>

          </id>

          "max_lo"”是id取值區(qū)間,每次插入記錄時(shí),生成器會(huì)根據(jù)此值步長(zhǎng)增長(zhǎng)。如果我們執(zhí)行的一次插入操作,插入了10條記錄。那么就需要將此設(shè)置為10,以便生成器自動(dòng)為我們生成10個(gè)不同的id

           

           

          2.多對(duì)多檢索策略

                   在以前的學(xué)習(xí)中,我們知道多對(duì)多關(guān)聯(lián)關(guān)系需要一個(gè)中間表,用于記錄兩個(gè)多對(duì)多表的對(duì)應(yīng)主鍵。反應(yīng)到映射文件中,我們需要為兩個(gè)類(lèi)添加set元素。我們依然使用,老師與學(xué)生的例子,一個(gè)老師可以有多個(gè)學(xué)生,一個(gè)學(xué)生可以有多個(gè)老師,映射文件如下:

          老師類(lèi)映射文件中的set元素:

          <set name="stus" table="hib_tea_stu_links" lazy="false">

                 <key column="tid" />

                 <many-to-many class="Stu" column="sid" />

          </set>

          column="tid"”對(duì)應(yīng)中間表“hib_tea_stu_links”的老師外鍵。“column="sid"”對(duì)應(yīng)中間表“hib_tea_stu_links”學(xué)生的外鍵。

          學(xué)生類(lèi)映射文件中的set元素:

          <set name="teas" table="hib_tea_stu_links" lazy="false" inverse="true">

                 <key column="sid" />

                 <many-to-many class="Tea" column="tid" />

          </set>

           

           

          檢索策略

          優(yōu)點(diǎn)

          缺點(diǎn)

          優(yōu)先考慮使用的場(chǎng)合

          立即檢索

          對(duì)應(yīng)用程序完全透明,不管對(duì)象處于持久化狀態(tài)還是游離狀態(tài),應(yīng)用程序都可以從一個(gè)對(duì)象導(dǎo)航到關(guān)聯(lián)的對(duì)象

          (1)select語(yǔ)句多

          (2)可能會(huì)加載應(yīng)用程序不需要訪問(wèn)的對(duì)象,浪費(fèi)許多內(nèi)存空間。

          (1)類(lèi)級(jí)別

          (2)應(yīng)用程序需要立即訪問(wèn)的對(duì)象

          (3)使用了二級(jí)緩存

          延遲檢索

          由應(yīng)用程序決定需要加載哪些對(duì)象,可以避免執(zhí)行多余的select語(yǔ)句,以及避免加載應(yīng)用程序不需要訪問(wèn)的對(duì)象。因此能提高檢索性能,并節(jié)省內(nèi)存空間。

          應(yīng)用程序如果希望訪問(wèn)游離狀態(tài)的代理類(lèi)實(shí)例,必須保證她在持久化狀態(tài)時(shí)已經(jīng)被初始化。

          (1)一對(duì)多或者多對(duì)多關(guān)聯(lián)

          (2)應(yīng)用程序不需要立即訪問(wèn)或者根本不會(huì)訪問(wèn)的對(duì)象

          迫切左外連接檢索

          (1)對(duì)應(yīng)用程序完全透明,不管對(duì)象處于持久化狀態(tài)還是游離狀態(tài),都可從一個(gè)對(duì)象導(dǎo)航到另一個(gè)對(duì)象。

          (2)使用了外連接,select語(yǔ)句少

          (1)可能會(huì)加載應(yīng)用程序不需要訪問(wèn)的對(duì)象,浪費(fèi)內(nèi)存。

          (2)復(fù)雜的數(shù)據(jù)庫(kù)表連接也會(huì)影響檢索性能。

          (1)多對(duì)一或一對(duì)一關(guān)聯(lián)

          (2)需要立即訪問(wèn)的對(duì)象

          (3)數(shù)據(jù)庫(kù)有良好的表連接性能。

           

          二、Hibernate的檢索方式

          Hibernate的檢索方式:

          1.對(duì)象導(dǎo)航圖:根據(jù)映射文件檢索

          2.OID檢索:根據(jù)OID檢索

          3.HQL檢索:一種類(lèi)似于SQL語(yǔ)句的面向?qū)ο蟮?/span>hibernate檢索文本語(yǔ)句

          4.QBC檢索:相當(dāng)于將HQL分解為一個(gè)個(gè)對(duì)象的檢索方式

          5.本地SQL檢索:SQL語(yǔ)句

           

                   只有HQLQBC我們比較陌生,在此我們介紹一下:

          1.HQL語(yǔ)句

          session.createQuery("from Customer c where c.name = 'itcast' and c.age = 12");

          Customer:指向類(lèi)名

          c.name:為映射文件中property元素的name

          c.ge:為映射文件中property元素的age

          看到?jīng)]有,HQL與數(shù)據(jù)庫(kù)毫無(wú)關(guān)系。HQL操作的持久化類(lèi)的映射文件。

          HQL有三種查詢方式:

          1).使用參數(shù)名,如:

          //綁定參數(shù)(按照參數(shù)名稱綁定)

          q = s.createQuery("from Customer c where c.name = :a and c.age = :b");

          q.setString("a","itcast");

          q.setInteger("b",12);

          q.list();

          2).使用索引

          //綁定參數(shù)(按照參數(shù)索引位置綁定)

          q = s.createQuery("from Customer c where c.name = ? and c.age = ?");

          q.setString(0,"itcast");

          q.setInteger(1,12);

          q.list();

          3).命名查詢

          我們需要在映射文件中添加一個(gè)class的兄弟元素,這個(gè)元素可以添加在任意相關(guān)的映射文件中:

          <!-- 命名查詢 -->

          <query name="findCustomerByName">

              <![CDATA[from Customer c where c.name = ?]]>

          </query>

          我們?cè)诔绦蛑兄苯诱{(diào)用:

          //命名查詢(將查詢條件定義到影射文件中,從影射文件中提取查詢條件)

          q = s.getNamedQuery("findCustomerByName");

          q.setString(0, "t,om");

          q.list();

           

          4).特別的左外連接查詢:

          //左外連接查詢,集合中的每個(gè)元素都是對(duì)象數(shù)組

          s.createQuery("from Customer c left outer join c.orders").list();

          //迫切左外連接查詢,集合中的每個(gè)元素都是客戶對(duì)象

          list = s.createQuery("from Customer c left outer join fetch c.orders").list();

          Set<Customer> customers = new HashSet<Customer>(list);

          左外連接查詢返回值:list中每個(gè)元素都是一個(gè)具有兩個(gè)成員的數(shù)組。數(shù)組[0]Customer對(duì)象,數(shù)組[1]Order對(duì)象。

          迫切左外連接返回值:list中每個(gè)元素都是一個(gè)Customer對(duì)象。

           

          2.QBC語(yǔ)句

          我們將上面的HQL語(yǔ)句,使用QBC來(lái)實(shí)現(xiàn):

          Criteria cra = s.createCriteria(Customer.class);

          Criterion ctn_name = Restrictions.eq("name", "itcast");

          Criterion ctn_age = Restrictions.eq("age", 12);

          //調(diào)用list時(shí)執(zhí)行查詢并返回值

          list = cra.add(ctn_name).add(ctn_age).list();

          QBC語(yǔ)句,一般用于動(dòng)態(tài)查詢。比如,WEB應(yīng)用中的高級(jí)搜索功能!

           

          上面介紹的都是相對(duì)簡(jiǎn)單的查詢。至于復(fù)雜的查詢,我想玩過(guò)數(shù)據(jù)庫(kù)的人一想就明白了。

           

          比較方面

          HQL檢索

          QBC檢索

          可讀性

          優(yōu)點(diǎn):和sql相近,易讀

          將語(yǔ)句肢解成一組criteria,較差

          功能

          支持各種查詢

          不支持報(bào)表查詢和子查詢。有限的連接查詢

          查詢語(yǔ)句形式

          基于字符串形式的sql

          更加面向?qū)ο?/span>

          何時(shí)被解析

          運(yùn)行時(shí)被解析

          編譯時(shí)被解析,更易排錯(cuò)

          可擴(kuò)展性

          不具擴(kuò)展性

          用戶可擴(kuò)展criteria接口

          對(duì)動(dòng)態(tài)查詢語(yǔ)句的支持

          支持動(dòng)態(tài)查詢,編程麻煩

          適合動(dòng)態(tài)生成查詢語(yǔ)句

           

           

           

          三、Hibernate的映射繼承關(guān)系

          就是前邊檢索策略中提到的:

          joined-subclassunion-subclasssubclass這些元素。

           

          四、Hibernate批量操作

          使用HQLQBC等查詢語(yǔ)句進(jìn)行批量操作

           

          五、Hibernate的緩存

                   二級(jí)緩存位于SessionFactory中,用于進(jìn)程范圍:多個(gè)工作單元共享,可并發(fā)訪問(wèn),可存儲(chǔ)實(shí)例本身也可存散列數(shù)據(jù),然后在重新組裝成對(duì)象放到一級(jí)緩存中。集群范圍:多個(gè)進(jìn)程和主機(jī)間訪問(wèn),網(wǎng)絡(luò)通信是重點(diǎn)。需要將數(shù)據(jù)復(fù)制到所有集群中的節(jié)點(diǎn)。

           

          1. Hibernate緩存基礎(chǔ)

               緩存不是JPAEJB規(guī)范,用于性能優(yōu)化,不同廠商方案不同。

               緩存維護(hù)數(shù)據(jù)狀態(tài)在本地,內(nèi)存或者磁盤(pán)。

               緩存會(huì)減少數(shù)據(jù)庫(kù)訪問(wèn)。

           

          2.緩存策略與范圍

               緩存類(lèi)型

               .事務(wù)范圍:位于當(dāng)前工作單元,不能并發(fā)訪問(wèn)。

               .進(jìn)程范圍:多個(gè)工作單元共享,可并發(fā)訪問(wèn),可存儲(chǔ)實(shí)例本身也可存散列數(shù)據(jù),然后在               重新組裝。

               .集群范圍:多個(gè)進(jìn)程和主機(jī)間訪問(wèn),網(wǎng)絡(luò)通信是重點(diǎn)。需要將數(shù)據(jù)復(fù)制到所有集群中的節(jié)點(diǎn)。

           

               緩存和OID

               事務(wù)級(jí)緩存也用于對(duì)象id的使用范圍,是理想的緩存。

               進(jìn)程級(jí)緩存可選擇實(shí)現(xiàn)id的進(jìn)程范圍存儲(chǔ),也和主鍵對(duì)應(yīng)。并發(fā)工作單元查詢同一id對(duì)象的話返     回相同的實(shí)例。在進(jìn)程級(jí)緩存中的對(duì)象也可按值返回,每個(gè)工作單元再重新組裝形成副本。

           

                   一級(jí)緩存是強(qiáng)制的,他也維護(hù)了OID,二級(jí)緩存(進(jìn)程級(jí)/集群級(jí))對(duì)某些數(shù)據(jù)來(lái)說(shuō)是有用的。

           

          3.緩存的架構(gòu)

                   1、一級(jí)緩存即session

               2、二級(jí)緩存是可配的插件,可用于進(jìn)程/集群范圍緩存。他們緩存都是狀態(tài)(按值返回),而不是真正的持久化對(duì)象。對(duì)于特定的數(shù)據(jù)項(xiàng)來(lái)說(shuō)緩存的并發(fā)策略定義了事務(wù)的隔離細(xì)節(jié)。每個(gè)類(lèi)或者每個(gè)集合的二級(jí)緩存是可選可配的。每個(gè)緩存都使用了自己的緩存區(qū)域。

               3Hibernate還實(shí)現(xiàn)了對(duì)查詢結(jié)果集的緩存,他和二級(jí)緩存緊密結(jié)合.而且需要額外的兩個(gè)物理緩存區(qū)域來(lái)容納緩存的查詢結(jié)果和最后更新表的時(shí)間戳。

           

          1.Hibernate二級(jí)緩存

           1、所有通過(guò)同一SessionFactory開(kāi)啟的會(huì)話共享同一二級(jí)緩存。

           2、對(duì)象以拆解的形式存于二級(jí)緩存中(拆解是串行化過(guò)程,算法更多,更快比java串行)

           3、重點(diǎn)在于緩存方案(緩存策略與物理緩存提供商)

           4、不同數(shù)據(jù)需要不同的緩存方案。涉及如下設(shè)置:

                     a、是否開(kāi)啟二級(jí)緩存

                     bHibernate并發(fā)策略

                     c、緩存過(guò)期策略(timerout LRU 內(nèi)存敏感)

                     d、緩存的物理格式(內(nèi)存 索引文件 集群替換)

           

          二級(jí)緩存安裝需要兩步:

          1、決定使用哪個(gè)緩存并發(fā)策略

          2、配置緩存過(guò)期和物理緩存屬性(cache provider)

           

          2).內(nèi)置并發(fā)策略

               并發(fā)策略是調(diào)解人,負(fù)責(zé)在緩存中檢索數(shù)據(jù)。對(duì)于特定數(shù)據(jù)項(xiàng),他也定義了事務(wù)隔離的語(yǔ)義。對(duì)類(lèi)     或集合來(lái)說(shuō)使用哪個(gè)并發(fā)策略需要做出判斷。

               四個(gè)內(nèi)置的并發(fā)策略體現(xiàn)了遞減的事務(wù)隔離的等級(jí)。

               1Transationsal

                  只在受管環(huán)境中使用,如果需要可以確保所有的事務(wù)隔離到可重復(fù)讀,很少更新且防止臟數(shù)        據(jù)情況下該策略很重要

               2Read-write

                  該策略維護(hù)讀已提交隔離級(jí)別,使用了時(shí)間戳機(jī)制只在非集群環(huán)境下使用。

               3Nostrict-read-write

                  不保證在數(shù)據(jù)庫(kù)和緩存之間數(shù)據(jù)的一致性,如果使用的話,應(yīng)該配置一個(gè)高效短期的過(guò)期超        時(shí)。否則,可能讀到臟數(shù)據(jù)。

               4Read-only

                  適用于從不發(fā)生改變的數(shù)據(jù)。只對(duì)數(shù)據(jù)進(jìn)行引用。約束的降低帶來(lái)了性能提升。

           

               還可以實(shí)現(xiàn)自定義策略:

               orghibernatecacheCacheConcurrencyStrategy

           

          3). 選擇緩存供應(yīng)商

               Hibernate要求必須為整個(gè)應(yīng)用選擇一個(gè)供應(yīng)商。以下是開(kāi)源的實(shí)現(xiàn):

               1EHCache

                  適用于單個(gè)虛擬機(jī)中單個(gè)進(jìn)程范圍,可緩存至內(nèi)存和磁盤(pán),支持查詢緩存(最新版本支持集群

                  緩存,未測(cè)試)

               2OpenSymphony OSCache

                  在單個(gè)虛擬機(jī)中緩存至內(nèi)存或磁盤(pán)。支持豐富的過(guò)期策略和查詢緩存。

               3SwarmCache

                  基于JGROUPS的集群緩存, 不支持Hibernate查詢緩存

               4JBoss Cache

                  同樣基于JGROUPS廣播庫(kù)的完全事務(wù)性自我復(fù)制集群緩存,支持自我復(fù)制、校驗(yàn)、同/異步

                  通信、樂(lè)觀/ 悲觀鎖

           

          二級(jí)緩存講的有些快,內(nèi)部實(shí)現(xiàn)原理沒(méi)講,因?yàn)闀r(shí)間來(lái)不急了。至于二級(jí)緩存的詳細(xì)配置與實(shí)現(xiàn)有的是以后有時(shí)間再自學(xué)吧!

           

          今天的日志主要使用了老徐的資料,在檢索策略那塊還好,因?yàn)橹v的比較細(xì)。之后的主要就是緩存技術(shù),一級(jí)緩存學(xué)的挺好,就這個(gè)二級(jí)緩存留有些“懸念”。

           

                   老徐是一位優(yōu)秀的老師,傳智播客確實(shí)很牛。能留住這么多人才!

           

                   明天就開(kāi)始學(xué)習(xí)luncene了,期待它的到來(lái)!

           

                   加油!


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 房产| 永年县| 岐山县| 伊宁县| 资源县| 尉犁县| 汶川县| 苏尼特左旗| 若羌县| 县级市| 邳州市| 葵青区| 赤水市| 新丰县| 荃湾区| 香格里拉县| 上饶县| 淅川县| 沭阳县| 余江县| 通化市| 巴青县| 台湾省| 大关县| 京山县| 岑溪市| 壤塘县| 定州市| 开远市| 三台县| 彭州市| 湄潭县| 嘉禾县| 佛冈县| 新津县| 祁阳县| 大庆市| 印江| 建水县| 金阳县| 肇东市|