欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java Hibernate中使用HQL語句進行數(shù)據(jù)庫查詢的要點解析

 更新時間:2016年06月24日 08:59:12   作者:zhang_xinxiu  
HQL是Hibernate框架中提供的關系型數(shù)據(jù)庫操作腳本,當然我們也可以使用原生的SQL語句,這里我們來看一下在Java Hibernate中使用HQL語句進行數(shù)據(jù)庫查詢的要點解析:

一、實體對象查詢

實體對象查詢是hql查詢的基礎,作為一種對象查詢語言,在查詢操作時和sql不同,查詢字符串中的內容要使用類名和類的屬性名來代替。這種查詢方法相對簡單,只要有SQL功底,使用hql是很簡單的,但是有一些問題需要注意,就是查詢獲取數(shù)據(jù)不是目的,需要考慮的是如何編寫出高效的查詢語句,這才是討論的重點。

1.N+1問題

(1)什么是N+1問題
在剛聽到這個名詞時疑惑可能是有的,以前根本就沒有聽過N+1問題,那么它是指什么呢?N+1指的是一張表中有N條數(shù)據(jù),那么在獲取這N條數(shù)據(jù)時會產(chǎn)生N+1條sql命令,這種操作被稱為N+1。這里的1指的是發(fā)出一條查詢id列表的語句,N則指根據(jù)id發(fā)出N條sql語句,加載相關的對象。這種查詢操作效率很低,往往產(chǎn)生在迭代器中,也就是說如果我們將查詢結果直接轉化為迭代器,這時候就會出現(xiàn)這種問題,如下代碼:

public void testQuery(){ 
  Session session=null; 
   
  try{ 
    session=HibernateUtils.getSession(); 
    session.beginTransaction(); 
     
    /** 
     * 會出現(xiàn)N+1問題,所謂的N+1值得是發(fā)出了N+1條sql語句 
     * 
     * 1:發(fā)出一條查詢id列表的語句 
     * 
     * N:根據(jù)id發(fā)出N條sql語句,加載相關的對象 
     */ 
    Iterator iter=session.createQuery("from Student").iterate(); 
     
    while(iter.hasNext()){ 
      Student student=(Student)iter.next(); 
      System.out.println(student.getName()); 
    } 
    session.getTransaction().commit(); 
  }catch(Exception e){ 
    e.printStackTrace(); 
    session.getTransaction().rollback(); 
  }finally{ 
    HibernateUtils.closeSession(session); 
  } 
} 

上面的這段查詢代碼就會產(chǎn)生N+1問題,因為查詢時返回的是一個迭代器,這樣沒產(chǎn)生一次就會發(fā)出一條sql語句,這主要取決于Iterator的這種查詢機制,它是從緩存中查詢數(shù)據(jù),如果緩存中不存在該數(shù)據(jù)那么首先會將數(shù)據(jù)轉換到內存中,所以這時候就會發(fā)出一條sql查詢語句,所以在每次迭代時就會產(chǎn)生一條sql語句。這種寫法其實是一種錯誤,可以使用其它方法優(yōu)化解決。

(2)避免N+1問題
出現(xiàn)了N+1的問題是因為Iterate使用不當?shù)脑颍斎豢梢允褂闷渌姆椒▉肀苊膺@種N+1的問題,這里介紹一種List的方法。List和Iterate最大的區(qū)別是List將數(shù)據(jù)放到緩存中,但是不利用緩存,默認情況下list每次都會發(fā)出sql語句。可以在使用Iterate之前,使用list將數(shù)據(jù)保存到數(shù)據(jù)庫中,這樣Iterate訪問數(shù)據(jù)時就可以從緩存中讀取,避免了N+1問題的出現(xiàn),代碼如下:

public void testQuery(){ 
  Session session=null; 
   
  try{ 
    session=HibernateUtils.getSession(); 
    session.beginTransaction(); 
     
    List students=session.createQuery("from Student").list(); 
     
     
    System.out.println("---------------------------------"); 
    /** 
     * 避免了N+1問題 
     * 
     * 因為執(zhí)行l(wèi)ist操作后會將數(shù)據(jù)放到session的緩存中(一級緩存),所以采用iterate的時候 
     * 首先會發(fā)出一條查詢id列表的語句,再根據(jù)id到緩存中加載相應的數(shù)據(jù),如果緩存中存在與之匹配的數(shù)據(jù) 
     * 則不再發(fā)出根據(jù)id查詢的sql語句,直接使用緩存中的數(shù)據(jù) 
     * 
     * Iterate方法如果緩存中存在數(shù)據(jù),它可以提高性能,否則出現(xiàn)N+1問題 
     */ 
    //可以使用as別名 
    Iterator iter=session.createQuery("from Student").iterate(); 
     
    while(iter.hasNext()){ 
      Student student=(Student)iter.next(); 
      System.out.println(student.getName()); 
    } 
    session.getTransaction().commit(); 
  }catch(Exception e){ 
    e.printStackTrace(); 
    session.getTransaction().rollback(); 
  }finally{ 
    HibernateUtils.closeSession(session); 
  } 
} 

上例 避免了N+1問題,因為執(zhí)行l(wèi)ist操作后會將數(shù)據(jù)放到session的緩存中(一級緩存),所以采用iterate的時候首先會發(fā)出一條查詢id列表的語句,再根據(jù)id到緩存中加載相應的數(shù)據(jù),如果緩存中存在與之匹配的數(shù)據(jù), 則不再發(fā)出根據(jù)id查詢的sql語句,直接使用緩存中的數(shù)據(jù)。 Iterate方法如果緩存中存在數(shù)據(jù),它可以提高性能,否則出現(xiàn)N+1問題。

2.對象導航查詢

對象導航是指在一個對象中按照對象的屬性導航獲取到另一個對象的數(shù)據(jù),這樣做可以簡化查詢語句,優(yōu)化查詢方法。如果按照我們平常的想法可能會再重寫編寫另一個類的對象,來獲取另一個對象的操作,和對象導航對比語句比較累贅。

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public void testQuery1(){ 
  Session session=null; 
   
  try{ 
    session=HibernateUtils.getSession(); 
    session.beginTransaction(); 
     
    //返回結果集屬性列表,元素類型和實體類中的屬性類型一致 
    List students=session.createQuery("from Student s where s.classes.name like '%2%'").list(); 
     
    for(Iterator ite=students.iterator();ite.hasNext();){ 
      Student obj=(Student)ite.next(); 
      System.out.println(obj.getName()); 
    } 
       
    session.getTransaction().commit(); 
  }catch(Exception e){ 
    e.printStackTrace(); 
    session.getTransaction().rollback(); 
  }finally{ 
    HibernateUtils.closeSession(session); 
  } 
} 

上例中的查詢語句就使用了對象導航的方法,查詢語句是從Student對象中查詢的信息,但是要比對的對象屬性卻是來自于Classes對象的name屬性,這時候使用對象導航的查詢方法就會明顯提高查詢效率,優(yōu)化查詢語句,如果換做普通的查詢方法就可能會產(chǎn)生大量的連接語句,很復雜。

二、sql原生查詢

原生查詢值的是使用SQL語句來查詢獲取數(shù)據(jù),而不是采用hql語句,它的使用方法其實很簡單,同hql類似,只需要使用createSQLQuery方法查詢即可,它其實類似于hql的createQuery方法,代碼如下:

public void testQeury(){ 
  Session session=null; 
  try{ 
    session=HibernateUtils.getSession(); 
    session.beginTransaction(); 
     
    List list=session.createSQLQuery("select * from t_student").list(); 
     
    for(Iterator ite=list.iterator();ite.hasNext();){ 
      Object[] obj=(Object[])ite.next(); 
      System.out.println(obj[0]+","+obj[1]); 
    } 
     
    session.getTransaction().commit(); 
  }catch(Exception e){ 
    e.printStackTrace(); 
    session.getTransaction().rollback(); 
  }finally{ 
    HibernateUtils.closeSession(session); 
  } 
} 

上面的代碼使用了createSQLQuery方法,方法內的查詢字符串就是SQL語句,它實現(xiàn)了底層的字符串查詢方法,不同的是HQL又做了一層包裝,在Hibernate.cfg.xml中配置相應的方言選項即可完成映射。

三、連接查詢

在sql中經(jīng)常使用連接查詢來獲取多個對象的合集,其中經(jīng)常用到的有inner join、left join、right join等,分別指代內連接查詢、左外連接查詢、右外連接查詢,它們在查詢時返回的內容分別是實體之間的笛卡爾積,查詢的內容及左表的一些內容,查詢內容及右表的一些內容,查詢的功能強大。hql的連接查詢方法和sql的連接查詢在查詢結果上是相同的,但是在查詢語句上稍有區(qū)別。

1.內連接

hql的內連接查詢可使用inner join語句或者join語句查詢,獲取的結果集是笛卡爾積。同sql的內連接查詢類似,hql的join查詢又分為顯式與隱式兩種,顯示的查詢是指查詢字符串中有join關鍵字,隱式的查詢在字符串中不需要添加join。

//內連接 
@SuppressWarnings({ "unchecked", "rawtypes" }) 
public void testQuery(){ 
  Session session=null; 
   
  try{ 
    session=HibernateUtils.getSession(); 
    session.beginTransaction(); 
     
    //返回結果集屬性列表,元素類型和實體類中的屬性類型一致 
    List students=session.createQuery("select s.name,c.name from Student s join s.classes c").list(); 
     
    for(Iterator ite=students.iterator();ite.hasNext();){ 
      Object[] obj=(Object[])ite.next(); 
      System.out.println(obj[0]); 
    } 
     
    session.getTransaction().commit(); 
  }catch(Exception e){ 
    e.printStackTrace(); 
    session.getTransaction().rollback(); 
  }finally{ 
    HibernateUtils.closeSession(session); 
  } 
} 


2.外連接
外連接又分為左外連接和右外連接查詢,查詢方法類似,但是查詢出的結果集不同,它們在查詢結果上和SQL的外連接相同,不同的是寫法,具體使用代碼如下:

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public void testQuery(){ 
  Session session=null; 
   
  try{ 
    session=HibernateUtils.getSession(); 
    session.beginTransaction(); 
     
    //返回結果集屬性列表,元素類型和實體類中的屬性類型一致 
    List students=session.createQuery("select s.name,c.name from Student s left join s.classes c").list(); 
     
    for(Iterator ite=students.iterator();ite.hasNext();){ 
      Object[] obj=(Object[])ite.next(); 
      System.out.println(obj[0]); 
    } 
     
    session.getTransaction().commit(); 
  }catch(Exception e){ 
    e.printStackTrace(); 
    session.getTransaction().rollback(); 
  }finally{ 
    HibernateUtils.closeSession(session); 
  } 
} 

上面的代碼使用的是左外連接查詢語句,相應的右外連接查詢的方法和左外連接類似,將left轉換為right即可。查詢到的數(shù)據(jù)被保存到list對象中,可通過list來獲取查詢內容。

四、外置命名查詢

外置命名查詢是指將查詢語句寫到映射文件中,在映射文件中使用<query>標簽來定義hql語句,這樣定義的hql語句就能夠實現(xiàn)功能配置功能,如果出現(xiàn)問題只需要修改配置即可。如果想用使用該sql語句,可在程序中使用session.getNamedQuery()方法得到hql查詢串,如下示例。

1.外置查詢語句
下面示例中演示了外置查詢語句的應用,在映射文件中添加<query>標簽,并為該標簽添加name屬性,將字符串添加到<![CDATA[]]>中,這樣既可在程序中按照query的name屬性獲取對應的查詢字符串了。

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC  
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping> 
  <class name="com.src.hibernate.Student" table="t_student"> 
    <id name="id"> 
      <generator class="native"/> 
    </id> 
    <property name="name"/> 
    <property name="createTime"></property> 
    <!-- 在多的一端Student中添加一行新的Classes列 ,并且列的名稱要和Classes.hbm.xml的列明相同--> 
    <many-to-one name="classes" column="classesid"></many-to-one> 
  </class> 
   
  <query name="queryStudent"> 
    <![CDATA[ 
      select s from Student s where s.id<? 
    ]]> 
  </query> 
   
</hibernate-mapping> 

外置的命名查詢將查詢語句放到了映射文件中,所以它可以被認為是公共的查詢字符串,在程序文件中都可以查詢使用該字符串,這是它的優(yōu)點,這樣其它的程序文件就都可以獲取使用了,另外作為公共的字符串增加了修改的便利性。

2.程序應用

定義了外置的查詢語句后要在程序中使用,hql提供了getNameQuery方法來獲取外置的查詢語句串,該方法中需要添加一個外置的游標名稱,hql會根據(jù)游標名稱查詢獲取相對應的sql語句塊,如下的程序代碼:

//外置命名查詢 
@SuppressWarnings({ "unchecked", "rawtypes" }) 
public void testQuery(){ 
  Session session=null; 
   
  try{ 
    session=HibernateUtils.getSession(); 
    session.beginTransaction(); 
     
    List students=session.getNamedQuery("queryStudent").setParameter(0, 10).list(); 
     
    for(Iterator ite=students.iterator();ite.hasNext();){ 
      Student obj=(Student)ite.next(); 
      System.out.println(obj.getName()); 
    } 
     
    session.getTransaction().commit(); 
  }catch(Exception e){ 
    e.printStackTrace(); 
    session.getTransaction().rollback(); 
  }finally{ 
    HibernateUtils.closeSession(session); 
  } 
} 

相關文章

  • Spring @Configuration和@Component的區(qū)別

    Spring @Configuration和@Component的區(qū)別

    今天小編就為大家分享一篇關于Spring @Configuration和@Component的區(qū)別,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • 通過Java代碼來創(chuàng)建view的方法

    通過Java代碼來創(chuàng)建view的方法

    本文給大家分享通過java代碼創(chuàng)建view的方法,以TextView為例創(chuàng)建控件的方法,需要的的朋友參考下吧
    2017-08-08
  • springboot整合springsecurity與mybatis-plus的簡單實現(xiàn)

    springboot整合springsecurity與mybatis-plus的簡單實現(xiàn)

    Spring Security基于Spring開發(fā),項目中如果使用Spring作為基礎,配合Spring Security做權限更加方便,而Shiro需要和Spring進行整合開發(fā)。因此作為spring全家桶中的Spring Security在java領域很常用
    2021-10-10
  • 淺談java IO流——四大抽象類

    淺談java IO流——四大抽象類

    這篇文章主要介紹了java IO流——四大抽象類,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • java調用微信現(xiàn)金紅包接口的心得與體會總結

    java調用微信現(xiàn)金紅包接口的心得與體會總結

    這篇文章主要介紹了java調用微信現(xiàn)金紅包接口的心得與體會總結,有需要的朋友可以了解一下。
    2016-11-11
  • Java程序運行之JDK,指令javac java解讀

    Java程序運行之JDK,指令javac java解讀

    這篇文章主要介紹了Java程序運行之JDK,指令javac java,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • java實現(xiàn)微信App支付服務端

    java實現(xiàn)微信App支付服務端

    這篇文章主要為大家詳細介紹了java實現(xiàn)微信App支付服務端,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • 老生常談Java異常處理和設計(推薦)

    老生常談Java異常處理和設計(推薦)

    下面小編就為大家?guī)硪黄仙U凧ava異常處理和設計(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 一步步教你把SpringBoot項目打包成Docker鏡像

    一步步教你把SpringBoot項目打包成Docker鏡像

    Docker可以讓開發(fā)者打包他們的應用以及依賴包到一個輕量級、可移植的容器中,然后發(fā)布到任何流行的 Linux 機器上,也可以實現(xiàn)虛擬化,下面這篇文章主要給大家介紹了關于SpringBoot項目打包成Docker鏡像的相關資料,需要的朋友可以參考下
    2023-02-02
  • MybatisPlus中的save方法詳解

    MybatisPlus中的save方法詳解

    save方法是Mybatis-plus框架提供的一個添加記錄的方法,它用于將一個實體對象插入到數(shù)據(jù)庫表中,這篇文章主要介紹了MybatisPlus中的save方法,需要的朋友可以參考下
    2023-11-11

最新評論