Java Hibernate中應用HQL語句停止數據庫查詢的要點解析。本站提示廣大學習愛好者:(Java Hibernate中應用HQL語句停止數據庫查詢的要點解析)文章只能為提供參考,不一定能成為您想要的結果。以下是Java Hibernate中應用HQL語句停止數據庫查詢的要點解析正文
1、實體對象查詢
實體對象查詢是hql查詢的基本,作為一種對象查詢說話,在查詢操作時和sql分歧,查詢字符串中的內容要應用類名和類的屬性名來取代。這類查詢辦法絕對簡略,只需有SQL功底,應用hql是很簡略的,然則有一些成績須要留意,就是查詢獲得數據不是目標,須要斟酌的是若何編寫出高效的查詢語句,這才是評論辯論的重點。
1.N+1成績
(1)甚麼是N+1成績
在剛聽到這個名詞時困惑能夠是有的,之前基本就沒有聽過N+1成績,那末它是指甚麼呢?N+1指的是一張表中有N條數據,那末在獲得這N條數據時會發生N+1條sql敕令,這類操作被稱為N+1。這裡的1指的是收回一條查詢id列表的語句,N則指依據id收回N條sql語句,加載相干的對象。這類查詢操作效力很低,常常發生在迭代器中,也就是說假如我們將查詢成果直接轉化為迭代器,這時候候就會湧現這類成績,以下代碼:
public void testQuery(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); /** * 會湧現N+1成績,所謂的N+1值得是收回了N+1條sql語句 * * 1:收回一條查詢id列表的語句 * * N:依據id收回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); } }
下面的這段查詢代碼就會發生N+1成績,由於查詢時前往的是一個迭代器,如許沒發生一次就會收回一條sql語句,這重要取決於Iterator的這類查詢機制,它是從緩存中查詢數據,假如緩存中不存在該數據那末起首會將數據轉換到內存中,所以這時候候就會收回一條sql查詢語句,所以在每次迭代時就會發生一條sql語句。這類寫法實際上是一種毛病,可使用其它辦法優化處理。
(2)防止N+1成績
湧現了N+1的成績是由於Iterate應用欠妥的緣由,固然可使用其它的辦法來防止這類N+1的成績,這裡引見一種List的辦法。List和Iterate最年夜的差別是List將數據放到緩存中,然則晦氣用緩存,默許情形下list每次都邑收回sql語句。可以在應用Iterate之前,應用list將數據保留到數據庫中,如許Iterate拜訪數據時便可以從緩存中讀取,防止了N+1成績的湧現,代碼以下:
public void testQuery(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); List students=session.createQuery("from Student").list(); System.out.println("---------------------------------"); /** * 防止了N+1成績 * * 由於履行list操作後會將數據放到session的緩存中(一級緩存),所以采取iterate的時刻 * 起首會收回一條查詢id列表的語句,再依據id到緩存中加載響應的數據,假如緩存中存在與之婚配的數據 * 則不再收回依據id查詢的sql語句,直接應用緩存中的數據 * * Iterate辦法假如緩存中存在數據,它可以進步機能,不然湧現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成績,由於履行list操作後會將數據放到session的緩存中(一級緩存),所以采取iterate的時刻起首會收回一條查詢id列表的語句,再依據id到緩存中加載響應的數據,假如緩存中存在與之婚配的數據, 則不再收回依據id查詢的sql語句,直接應用緩存中的數據。 Iterate辦法假如緩存中存在數據,它可以進步機能,不然湧現N+1成績。
2.對象導航查詢
對象導航是指在一個對象中依照對象的屬性導航獲得到另外一個對象的數據,如許做可以簡化查詢語句,優化查詢辦法。假如依照我們平凡的設法主意能夠會再重寫編寫另外一個類的對象,來獲得另外一個對象的操作,和對象導航比較語句比擬包袱。
@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屬性,這時候候應用對象導航的查詢辦法就會顯著進步查詢效力,優化查詢語句,假如換做通俗的查詢辦法便可能會發生年夜量的銜接語句,很龐雜。
2、sql原生查詢
原生查詢值的是應用SQL語句來查詢獲得數據,而不是采取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語句,它完成了底層的字符串查詢辦法,分歧的是HQL又做了一層包裝,在Hibernate.cfg.xml中設置裝備擺設響應的方言選項便可完成映照。
3、銜接查詢
在sql中常常應用銜接查詢來獲得多個對象的合集,個中常常用到的有inner join、left join、right join等,分離指代內銜接查詢、左外銜接查詢、右外銜接查詢,它們在查詢時前往的內容分離是實體之間的笛卡爾積,查詢的內容及左表的一些內容,查詢內容及右表的一些內容,查詢的功效壯大。hql的銜接查詢辦法和sql的銜接查詢在查詢成果上是雷同的,然則在查詢語句上稍有差別。
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便可。查詢到的數據被保留到list對象中,可經由過程list來獲得查詢內容。
4、外置定名查詢
外置定名查詢是指將查詢語句寫到映照文件中,在映照文件中應用<query>標簽來界說hql語句,如許界說的hql語句就可以夠完成功效設置裝備擺設功效,假如湧現成績只須要修正設置裝備擺設便可。假如想用應用該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>
外置的定名查詢將查詢語句放到了映照文件中,所以它可以被以為是公共的查詢字符串,在法式文件中都可以查詢應用該字符串,這是它的長處,如許其它的法式文件就都可以獲得應用了,別的作為公共的字符串增長了修正的方便性。
2.法式運用
界說了外置的查詢語句後要在法式中應用,hql供給了getNameQuery辦法來獲得外置的查詢語句串,該辦法中須要添加一個外置的游標稱號,hql會依據游標稱號查詢獲得絕對應的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); } }