石頭JAVA擺地攤兒

          JAVA所有的討論-要一點一點的進(jìn)步

            BlogJava :: 首頁 ::  :: 聯(lián)系 ::  :: 管理 ::
            30 隨筆 :: 0 文章 :: 11 評論 :: 0 Trackbacks
          連接查詢:
             關(guān)系型數(shù)據(jù)庫之所以強(qiáng)大,其中一個原因就是可以統(tǒng)一使用表來管理同類數(shù)據(jù)信息,并且可以在相關(guān)數(shù)據(jù)之間建立關(guān)系。作為支持關(guān)系型數(shù)據(jù)庫的SQL語句來說,自然要對全面發(fā)揮這種強(qiáng)大功能提供支持,這個支持就是連接查詢。同樣作為一種關(guān)系型數(shù)據(jù)庫的持久層框架,Hibernate也對連接查詢提供了豐富的支持,在Hibernate中通過HQL與QBC兩種查詢方式都可以支持連接查詢。下面這一部分我們將通過這兩種查詢技術(shù),來詳細(xì)討論有關(guān)Hibernate對連接查詢支持的各個細(xì)節(jié)。在講解連接查詢之前,我們先來回憶一下在第一部分中講解的有關(guān)實體關(guān)聯(lián)關(guān)系的映射,在實體的配置文件中可以通過配置集合元素來指定對關(guān)聯(lián)實體的映射以及檢索策略。(請參考第一部分相關(guān)內(nèi)容)因此我們可以在實體映射配置文件中,指定關(guān)聯(lián)實體檢索策略,對關(guān)聯(lián)實體的檢索策略可以指定為“延遲檢索”,“立即檢索”,“迫切左外連接檢索”,如下所示對與Customer實體關(guān)聯(lián)的Order實體設(shè)置延遲加載:<set name=”orders” inverse=”true” lazy=”true”>,這種在實體映射配置文件中設(shè)定的檢索策略,稱為默認(rèn)檢索策略,但是這種默認(rèn)檢索策略是可以被覆蓋的,那就是在程序代碼當(dāng)中可以動態(tài)指定各種迫切檢索策略來覆蓋默認(rèn)檢索策略。
          1、    迫切左外連接查詢和左外連接查詢:
          我們看以下代碼,這段代碼將覆蓋映射文件中的檢索策略,顯示指定采用迫切左外連接查詢。
           
          HQL查詢方式:
          Query query=session.createQuery(“from Customer c left join fetch c.orders o where c.name       like ‘zhao%’ ”);
          List list=query.list();
          for(int i=0;i<list.size();i++){
           Customer customer=(Customer)list.get(i);
          }
          //QBC檢索方式:
          List list=session.createCriteria(Customer.class).setFetchMode(“orders”,FetchMode.EAGER)
                  .add(Expression.like(“name”,”zhao%”,MatchMode.START).list();
          for(int i=0;i<list.size();i++){
           Customer customer=(Customer)list.get(i);
          }
          我們看到在HQL以及QBC查詢中分別通過left join fetch和FetchMode.EAGER來指定采用迫切左外連接檢索策略,當(dāng)采用了迫切左外連接檢索策略時,當(dāng)進(jìn)行檢索時即執(zhí)行查詢的list()方法時,將會立即初始化用來容納關(guān)聯(lián)實體的集合對象元素,如果在實體映射配置文件中對關(guān)聯(lián)實體設(shè)置了延遲加載,那么此時將會忽略延遲加載設(shè)置,而采用迫切左外連接策略,并且立即用關(guān)聯(lián)實體對象填充集合對象元素,即使用Order對象填充Customer對象的orders集合。因此這種檢索策略會馬上創(chuàng)建關(guān)聯(lián)實體對象,此時我想你一定會想到這種檢索策略會同時檢索出Customer和Order實體對象對應(yīng)的數(shù)據(jù),并且分別創(chuàng)建這兩個對象。恭喜你答對了,因此上面代碼會生成類似如下的SQL語句:
          Select * from customer c left join order o on c.id=o.id where c.name like ‘zhao%’;
          如果我們忽略了fetch關(guān)鍵字,就變成了左外連接查詢,如下面代碼:
          Query query=session.createQuery(“from Customer c left join c.orders o where c.name       like ‘zhao%’ ”);
          List list=query.list();
          for(int i=0;i<list.size();i++){
           Object[] objs=(Object[])list.get(i);
           Customer customer=(Customer) objs[0];
           order order=(Order)objs[1];
          }
          我們可以看到采用左外連接查詢返回的結(jié)果集中包含的是對象數(shù)組,對象數(shù)組中的每個元素存放了一對相互關(guān)聯(lián)的Customer對象和Order對象,而迫切左外連接會返回Customer對象,與Customer對象相關(guān)聯(lián)的Order對象存放在Customer對象的集合元素對象中,這就是迫切左外連接和左外連接查詢的其中一個區(qū)別(這兩種檢索生成的SQL語句是一樣的),另一個區(qū)別是當(dāng)使用左外連接時,對關(guān)聯(lián)對象的檢索會依照實體映射配置文件所指定的策略,而不會像迫切左外連接那樣忽略它,比如此時對Customer對象關(guān)聯(lián)的Order對象采用延遲加載,那么左外連接檢索也會使用延遲加載機(jī)制檢索Order對象。
          2、內(nèi)連接,迫切內(nèi)連接以及隱式內(nèi)連接:
           若采用迫切內(nèi)連接通過一下代碼可以實現(xiàn):
          Query query=session.createQuery(“from Customer c inner join fetch c.orders o where c.name       like ‘zhao%’ ”);
          List list=query.list();
          for(int i=0;i<list.size();i++){
           Customer customer=(Customer)list.get(i);
          }
          這段代碼將會采用迫切內(nèi)連接檢索,對集合元素的檢索策略以及返回結(jié)果集中的對象類型都采用與迫切左外連接一樣的方式,我這里就不再贅述,另外QBC查詢不支持迫切內(nèi)連接檢索。
          如果去掉fetch就是內(nèi)連接檢索,如下面代碼:
          Query query=session.createQuery(“from Customer c innerjoin c.orders o where c.name       like ‘zhao%’ ”);
          List list=query.list();
          for(int i=0;i<list.size();i++){
           Object[] objs=(Object[])list.get(i);
           Customer customer=(Customer) objs[0];
           order order=(Order)objs[1];
          }
          內(nèi)連接檢索,對集合元素的檢索策略以及返回結(jié)果集中的對象類型都采用與左外連接一樣的方式,QBC查詢也同樣支持內(nèi)連接檢索,如下代碼:
          List list=session.createCriteria(Customer.class)
          .add(Expression.like(“name”,”zhao%”,MatchMode.START))
          .createCriteria(“orders”)
          .add(Expression.like(“ordernumber”,”T”,MatchMode.START)).list();
                上面代碼等價于如下的HQL語句:
                Select c from Customer c join c.orders o where c.name like ‘zhao%’ and o.ordernummber like ‘T%’;因此可以采用下面的方式訪問結(jié)果集:
          for(int i=0;i<list.size();i++){
           Customer customer=(Customer)list.get(i);
          }
                由此可見,采用內(nèi)連接查詢時,HQL與QBC查詢有不同的默認(rèn)行為,HQL會檢索出成對的Customer和Order對象,而QBC僅會檢索出Customer對象。如果QBC查詢想檢索出成對的Customer和Order對象,可以采用如下代碼:
          List list=session.createCriteria(Customer.class)
          .createAlias(“orders”,”o”)
          .add(Expression.like(“this.name”,”zhao%”,MatchMode.START))
          .add(Expression.like(“ordernumber”,”T”,MatchMode.START))
          .returnMap()
          .list();
          for(int i=0;i<list.size();i++){
             Map map=(Map)list.get(i);
           Customer customer=(Customer)map.get(“this”);
           order order=(Order)map.get(“o”);
          }
              “o”和”this”分別是orders集合和Customer對象的別名。
              在HQL查詢中,還有一種查詢成為隱式內(nèi)連接,我們看下面的HQL語句,
                From order o where o.customer.name like ’ zhao% ’;這個語句通過o.customer.name訪問與Order對象關(guān)聯(lián)的Customer對象的name屬性,盡管沒有使用join關(guān)鍵字,其實隱式指定了采用內(nèi)連接檢索,它和下面這條HQL語句等價:
          From order o join o.customer c where c.name like ‘zhao%’;
          隱式內(nèi)連接只適用于多對一和一對一關(guān)聯(lián),不適用于一對多和多對多關(guān)聯(lián),另外QBC查詢不支持隱式內(nèi)連接檢索。
          3、右外連接檢索:
          由于fetch關(guān)鍵字只能應(yīng)用于innner join和left join,因此對于右外連接檢索而言,就不存在所謂的迫切右外連接查詢了,使用右外連接見如下代碼:
          Query query=session.createQuery(“from Customer c right join c.orders o where c.name       like ‘zhao%’ ”);
          List list=query.list();
          for(int i=0;i<list.size();i++){
           Object[] objs=(Object[])list.get(i);
           Customer customer=(Customer) objs[0];
           order order=(Order)objs[1];
          }
                右外連接檢索,對集合元素的檢索策略以及返回結(jié)果集中的對象類型都采用與左外連接一樣的方式。
          4、交叉連接:
           對于不存在關(guān)聯(lián)關(guān)系的兩個實體對象,不能使用內(nèi)連接查詢,也不能使用外連接查詢,此時可以使用具有SQL風(fēng)格的交叉連接,如下面代碼:
          Select c.ID,c.name,c.age,o.ID,o.ordernumber,o.customer_ID
          From Customer c,Order o;
          這個HQL語句將會執(zhí)行交叉連接檢索,而且將會返回customer表和order表的笛卡兒積關(guān)聯(lián)結(jié)果。
          5、連接查詢運行時檢索策略總結(jié):
          ①、如果在HQL和QBC查詢中沒有指定檢索策略,那么將會使用映射配置為件中指定的檢索策略,但是這里有一個例外,那就是HQL檢索總是會忽略實體映射配置文件中對關(guān)聯(lián)實體指定的迫切左外連接檢索策略,也就是說如果配置文件中指定對關(guān)聯(lián)實體采用迫切走外連接檢索,但是在HQL查詢語句中沒有指定這種檢索策略,此時Hibernate將會忽略這種檢索策略,而依然采用立即檢索。因此如果希望采用迫切左外連接檢索,就必須在HQL語句中明確指定。
          ②、如果在HQL或者QBC檢索中明確指定了檢索策略,就會覆蓋配置文件中的默認(rèn)檢索策略,在HQL查詢中通過left join fetch和inner join fetch來明確指定檢索策略,在QBC查詢中通過FetchMode.DEFAULT,FetchMode.EAGER,FetchMode.LAZY來明確指定檢索策略。
          ①、             目前的Hibernate的各種版本中,只允許在一個查詢中迫切左外連接檢索一個集合,即只允許存在一個一對多關(guān)聯(lián),但是允許存在多個一對一和多對多關(guān)聯(lián)。
          posted on 2007-09-10 09:49 石頭JAVA擺地攤兒 閱讀(465) 評論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 黄石市| 克山县| 蒲江县| 共和县| 德江县| 西盟| 台南市| 台前县| 大洼县| 新河县| 盐亭县| 启东市| 社旗县| 日照市| 通辽市| 迁西县| 光山县| 青龙| 社旗县| 永登县| 阳高县| 连云港市| 靖远县| 新巴尔虎左旗| 江永县| 和平县| 革吉县| 汶川县| 梁平县| 大足县| 万宁市| 义马市| 黄石市| 富锦市| 陵川县| 水城县| 万宁市| 杭锦后旗| 温泉县| 鱼台县| 德清县|