15、HQL簡(jiǎn)介及演示數(shù)據(jù)初始化(1)(hibernate筆記)

主要內(nèi)容:

  • 簡(jiǎn)單屬性查詢
  • 實(shí)體對(duì)象查詢

一奏候、概述

  • 數(shù)據(jù)查詢與檢索是Hibernate中的一個(gè)兩點(diǎn)循集。相對(duì)其他ORM實(shí)現(xiàn)而言,Hibernate提供了靈活多樣的查詢機(jī)制蔗草。
  • 標(biāo)準(zhǔn)化對(duì)象查詢(Criteria Query):以對(duì)象的方式進(jìn)行查詢咒彤,將查詢語句封裝為對(duì)象操作。優(yōu)點(diǎn):可讀性好咒精,符合java程序員的編碼習(xí)慣镶柱。缺點(diǎn):不夠成熟,不支持投影(projection)或統(tǒng)計(jì)函數(shù)(aggregation)狠轻。
  • Hibernate語句查詢:是完全面向?qū)ο蟮牟樵冋Z句奸例,查詢功能非常強(qiáng)大,具備多態(tài)向楼、關(guān)聯(lián)等特性。Hibernate官方推薦使用HQL進(jìn)行查詢谐区。
  • Native SQL Queries(原生SQL查詢):直接使用標(biāo)準(zhǔn)SQL語言或跟特定數(shù)據(jù)庫(kù)相關(guān)的SQL進(jìn)行查詢湖蜕。

注意:在HQL中關(guān)鍵字不區(qū)分大小寫,但是屬性宋列、實(shí)體類名是區(qū)分大小寫的昭抒。

二、相關(guān)示例(工程hibernate_hql

相關(guān)映射和實(shí)體:
Student.java

private int id;
private String name;
private Date createTime;    
private Classes classes;

Classes.java

private int id;
private String name;
private Set students;

Student.hbm.xml

<?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="cn.itcast.hibernate.Student" table="_student">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <property name="createTime"/>
        <many-to-one name="classes" column="classesid"/>
    </class>
</hibernate-mapping>

Classes.hbm.xml

<?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 package="cn.itcast.hibernate">
    <class name="Classes" table="_classes">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <set name="students" inverse="true" cascade="all">
            <key column="classesid"/>
            <one-to-many class="Student"/>
        </set>
    </class>
</hibernate-mapping>

初始化
InitData.java

package cn.itcast.hibernate;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
public class InitData {

    public static void main(String[] args) {
            Session session = HibernateUtils.getSession();

            try {
                session.beginTransaction();

                for(int i=0; i<10; i++){
                
                    Classes classes = new Classes();
                    classes.setName("班級(jí)"+i);
                    session.save(classes);
                    
                    for(int j=0; j<10; j++){
                        Student student = new Student();
                        student.setName("班級(jí)"+i+"的學(xué)生"+j);
                        student.setCreateTime(randomDate("2008-01-01","2008-03-01"));
                        
                        //在內(nèi)存中建立由student指向classes的引用
                        student.setClasses(classes);
                        session.save(student);
                    }
                }
                
                for(int i=0; i<5; i++){
                    Classes classes = new Classes();
                    classes.setName("無學(xué)生班級(jí)"+i);
                    session.save(classes);
                }
                
                for(int i=0; i<10; i++){
                    Student student = new Student();
                    student.setName("無業(yè)游民"+i);
                    session.save(student);
                }
                
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally{
                HibernateUtils.closeSession(session);
            }
        }   
        
        /**
         * 獲取隨機(jī)日期
         * @param beginDate 起始日期炼杖,格式為:yyyy-MM-dd
         * @param endDate 結(jié)束日期灭返,格式為:yyyy-MM-dd
         * @return
         */
        private static Date randomDate(String beginDate,String endDate){
            try {
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                Date start = format.parse(beginDate);
                Date end = format.parse(endDate);
                
                if(start.getTime() >= end.getTime()){
                    return null;
                }
                
                long date = random(start.getTime(),end.getTime());
                
                return new Date(date);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        
        private static long random(long begin,long end){
            long rtn = begin + (long)(Math.random() * (end - begin));
            if(rtn == begin || rtn == end){
                return random(begin,end);
            }
            return rtn;
        }
}

2.1簡(jiǎn)單屬性查詢【重點(diǎn)】

  • 單一屬性查詢,返回結(jié)果集屬性列表坤邪,元素類型和實(shí)體類中相應(yīng)的屬性類型一致熙含。

  • 多個(gè)屬性查詢,返回的的集合元素是對(duì)象數(shù)組艇纺,數(shù)組元素的類型和相應(yīng)的屬性在實(shí)體中的類型一致怎静,數(shù)組的長(zhǎng)度取決于與select中屬性的個(gè)數(shù)邮弹。

  • 如果認(rèn)為返回?cái)?shù)組不夠?qū)ο蠡梢圆捎肏QL動(dòng)態(tài)實(shí)例化student對(duì)象蚓聘。

測(cè)試:
SimplePropertyQueryTest.java

package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import junit.framework.TestCase;
/**
 * 簡(jiǎn)單屬性查詢
 * @author Administrator
 */
public class SimplePropertyQueryTest extends TestCase {
    
    /**
     * 單一屬性查詢
     */
    public void testQuery1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //返回結(jié)果集屬性列表腌乡,元素類型和實(shí)體類中相應(yīng)的屬性類型一致
            List students = session.createQuery("select name from Student").list();
            for (Iterator iter=students.iterator(); iter.hasNext();) {
                String name = (String)iter.next();
                System.out.println(name);
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }
}

多個(gè)屬性查詢:

//查詢多個(gè)屬性,其集合元素是對(duì)象數(shù)組
//數(shù)組元素的類型和對(duì)應(yīng)的屬性在實(shí)體類中的類型一致
//數(shù)組的長(zhǎng)度取決與select中屬性的個(gè)數(shù)
List students = session.createQuery("select id, name from Student").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
    Object[] obj = (Object[])iter.next();
    System.out.println(obj[0] + "," + obj[1]);
}

返回Student實(shí)體對(duì)象

//如果認(rèn)為返回?cái)?shù)組不夠?qū)ο蠡鼓担梢圆捎胔ql動(dòng)態(tài)實(shí)例化Student對(duì)象
//此時(shí)list中為Student對(duì)象集合
List students = session.createQuery("select new Student(id, name) from Student").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
    Student student = (Student)iter.next();
    System.out.println(student.getId() + "," + student.getName());
}

使用別名

//可以使用別名1
List students = session.createQuery("select s.id, s.name from Student s").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
    Object[] obj = (Object[])iter.next();
    System.out.println(obj[0] + "," + obj[1]);
}
----------------------------------------------------------
//可以使用as命名別名
List students = session.createQuery("select s.id, s.name from Student as s").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
    Object[] obj = (Object[])iter.next();
    System.out.println(obj[0] + "," + obj[1]);
}

2.2實(shí)體對(duì)象查詢【重點(diǎn)】

  • N+1問題与纽,在默認(rèn)情況下,使用query.iterate查詢塘装,有可能出現(xiàn)N+1問題

  • 所謂的N+1是在查詢的時(shí)候發(fā)出了N+1條sql語句
    1:首先發(fā)出一條查詢語句去查詢對(duì)象id列表
    N:根據(jù)id列表到緩存中查詢渣锦,如果緩存中不存在與之匹配的數(shù)據(jù),那么會(huì)根據(jù)id發(fā)出相應(yīng)的sql語句

  • list和iterate的區(qū)別

    • list默認(rèn)情況下氢哮,每次都會(huì)發(fā)出sql語句袋毙,list會(huì)向緩存中放數(shù)據(jù),但是默認(rèn)是不利用緩存中的數(shù)據(jù)
    • iterate默認(rèn)情況下是會(huì)利用緩存冗尤,只有在緩存中沒有相應(yīng)的數(shù)據(jù)才會(huì)發(fā)出sql語句去數(shù)據(jù)庫(kù)中查詢听盖,即N+1問題。

測(cè)試:
SimpleObjectQueryTest1.java

    public void testQuery1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //返回Student對(duì)象的集合
            //可以忽略select
            List students = session.createQuery("from Student").list();
            for (Iterator iter=students.iterator(); 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);
        }
    }

使用別名

//返回Student對(duì)象的集合
//可以忽略select
List students = session.createQuery("from Student s").list();
//List students = session.createQuery("from Student as s").list();
//List students = session.createQuery("select s from Student as s").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
    Student student = (Student)iter.next();
    System.out.println(student.getName());
}

說明:第一種方式和第二種方式差不多裂七,最后一種注意必須使用別名(當(dāng)我么使用select的時(shí)候)皆看。最后注意,不支持
List students = session.createQuery("select * from Student").list();
這種方式背零,即不支持select * from ....腰吟。

SimpleObjectQueryTest2.java

package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import junit.framework.TestCase;
/**
 * 實(shí)體對(duì)象查詢
 * @author Administrator
 */
public class SimpleObjectQueryTest2 extends TestCase {

    public void testQuery1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            /**
             * 采用list查詢發(fā)出一條查詢語句,取得Student對(duì)象數(shù)據(jù)徙瓶、
             * Hibernate: select student0_.id as id1_, student0_.name as name1_, 
             * student0_.createTime as createTime1_, student0_.classesid as classesid1_ 
             * from t_student student0_
             * 
             */
            List students = session.createQuery("from Student").list();
            for (Iterator iter=students.iterator(); 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);
        }
    }
    
    public void testQuery2() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            /**
             * 出現(xiàn)N+1問題
             * 
             * 1:發(fā)出查詢id列表的sql
             *   Hibernate: select student0_.id as col_0_0_ from t_student student0_
             * 
             * N:在依次發(fā)出根據(jù)id查詢Student對(duì)象的sql
             * Hibernate: select student0_.id as id1_0_, student0_.name as name1_0_, 
             * student0_.createTime as createTime1_0_, student0_.classesid as classesid1_0_ 
             * from t_student student0_ where student0_.id=?
             *  
             */
            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);
        }
    }   
    
    public void testQuery3() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            List students = session.createQuery("from Student").list();
            for (Iterator iter=students.iterator(); iter.hasNext();) {
                Student student = (Student)iter.next();
                System.out.println(student.getName());
            }
            System.out.println("---------------------------------------------");
            
            /**
             * 不會(huì)出現(xiàn)N+1問題
             * 
             * 因?yàn)閘ist操作已經(jīng)將Student對(duì)象放到了一級(jí)緩存中毛雇,所以再次使用iterate操作的時(shí)候
             * 它首先發(fā)出一條查詢id列表的sql,在根據(jù)id到緩存中去數(shù)據(jù)侦镇,只有在緩存中找不到相應(yīng)的
             * 數(shù)據(jù)時(shí)灵疮,才會(huì)發(fā)出sql到數(shù)據(jù)庫(kù)中查詢
             * 
             */
            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);
        }
    }
    
    public void testQuery4() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            List students = session.createQuery("from Student").list();
            for (Iterator iter=students.iterator(); iter.hasNext();) {
                Student student = (Student)iter.next();
                System.out.println(student.getName());
            }
            System.out.println("---------------------------------------------");
            
            /**
             * 再次發(fā)出查詢sql
             * 
             * 在默認(rèn)情況下list每次都會(huì)向數(shù)據(jù)庫(kù)發(fā)出查詢對(duì)象的sql,除非配置查詢緩存壳繁,所以下面的list操作
             * 雖然在一級(jí)緩存中已經(jīng)有了對(duì)象數(shù)據(jù)震捣,但list默認(rèn)情況下不會(huì)利用緩存,而再次發(fā)出sql
             * 
             * 默認(rèn)情況下闹炉,list會(huì)向緩存中放入數(shù)據(jù)蒿赢,但不會(huì)利用數(shù)據(jù)
             * 
             */
            students = session.createQuery("from Student").list();
            for (Iterator iter=students.iterator(); 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);
        }
    }   
}

說明:

  • 1.對(duì)于方法一,我們可以看到使用list方法發(fā)出一條sql語句將所有的對(duì)象都查詢出來渣触。

  • 2.對(duì)于方法二羡棵,我們使用iterator方法進(jìn)行查詢,此時(shí)查詢就不一樣了昵观,先是發(fā)出一條sql語句將所有的id主鍵都查詢出來晾腔,然后根據(jù)主鍵去找相關(guān)的數(shù)據(jù)舌稀,首先在緩存中找,如果緩存中沒有對(duì)應(yīng)的數(shù)據(jù)灼擂,那么就會(huì)發(fā)出sql語句去數(shù)據(jù)庫(kù)中查詢壁查,于是就出現(xiàn)了N+1問題,因?yàn)樵诤竺鏁?huì)發(fā)出多條sql語句剔应,這樣對(duì)于數(shù)據(jù)庫(kù)的性能損耗是很大的睡腿。

  • 3.從方法三中我們也可以看到當(dāng)我們先使用list查詢出對(duì)象之后再使用iterator方法查詢就不會(huì)再次發(fā)出sql語句,因?yàn)閕terator方法會(huì)首先在緩存中找峻贮,而list方法已經(jīng)將相關(guān)數(shù)據(jù)放在了緩存中席怪,所以iterator方法不會(huì)再次發(fā)出sql語句,但是如果我們?cè)诤竺孢€是使用list方法而不是iterator方法纤控,那么還是會(huì)發(fā)出查詢語句挂捻,從方法四中可以看到,這就說明船万,iterator方法可以利用緩存刻撒,而list方法不會(huì)利用緩存。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末耿导,一起剝皮案震驚了整個(gè)濱河市声怔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舱呻,老刑警劉巖醋火,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異箱吕,居然都是意外死亡芥驳,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門殖氏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晚树,“玉大人,你說我怎么就攤上這事雅采。” “怎么了慨亲?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵婚瓜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我刑棵,道長(zhǎng)巴刻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任蛉签,我火速辦了婚禮胡陪,結(jié)果婚禮上沥寥,老公的妹妹穿的比我還像新娘。我一直安慰自己柠座,他們只是感情好邑雅,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著妈经,像睡著了一般淮野。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吹泡,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天骤星,我揣著相機(jī)與錄音,去河邊找鬼爆哑。 笑死洞难,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的揭朝。 我是一名探鬼主播队贱,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼萝勤!你這毒婦竟也來了露筒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤敌卓,失蹤者是張志新(化名)和其女友劉穎慎式,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體趟径,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘪吏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蜗巧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掌眠。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖幕屹,靈堂內(nèi)的尸體忽然破棺而出蓝丙,到底是詐尸還是另有隱情,我是刑警寧澤望拖,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布渺尘,位于F島的核電站,受9級(jí)特大地震影響说敏,放射性物質(zhì)發(fā)生泄漏鸥跟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望医咨。 院中可真熱鬧枫匾,春花似錦、人聲如沸拟淮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)惩歉。三九已至等脂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撑蚌,已是汗流浹背上遥。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留争涌,地道東北人粉楚。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像亮垫,于是被迫代替她去往敵國(guó)和親模软。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法饮潦,類相關(guān)的語法燃异,內(nèi)部類的語法,繼承相關(guān)的語法继蜡,異常的語法回俐,線程的語...
    子非魚_t_閱讀 31,664評(píng)論 18 399
  • Hibernate是一個(gè)開放源代碼的對(duì)象關(guān)系映射框架,它對(duì)JDBC進(jìn)行了非常輕量級(jí)的對(duì)象封裝稀并,它將POJO與數(shù)據(jù)庫(kù)...
    蘭緣小妖閱讀 1,214評(píng)論 1 18
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,814評(píng)論 0 11
  • 這部分主要是開源Java EE框架方面的內(nèi)容仅颇,包括Hibernate、MyBatis碘举、Spring忘瓦、Spring ...
    雜貨鋪老板閱讀 1,392評(píng)論 0 2
  • 作者:夏汐蕊?想看其他作品請(qǐng)點(diǎn)擊這里簡(jiǎn)書連載風(fēng)云錄 【第三十四章】命中已注定, 愛你今生不變(一) 今天引颈,是杜云帆...
    夏汐蕊閱讀 298評(píng)論 0 6