21菩掏、抓取策略(hibernate筆記)

一魂角、簡介

抓取策略是指:當(dāng)應(yīng)用程序需要在關(guān)聯(lián)關(guān)系間進行導(dǎo)航的時候,hibernate如何獲取關(guān)聯(lián)對象的策略。可以在O/R映射的元數(shù)據(jù)中聲明识埋,也可以在特定的hql或條件查詢中重載聲明反浓。有幾種策略:連接抓取(Join)烘豌、查詢抓取(Select)、子查詢抓日醵琛(subselect)、批量抓扰贡摺(batch)憎茂。其中查詢抓取是默認(rèn)的。

注意:下面的示例中所使用的實體和映射和前面查詢緩存中是一樣的锤岸。

二竖幔、單端代理的批量抓取

2.1使用select策略(工程hibernate_fetch_1

由于默認(rèn)是Select抓取策略,所以我們可以保持默認(rèn)是偷,或者也可以在Student.hbm.xml中進行配置:
<many-to-one name="classes" column="classesid" fetch="select"/>

測試:
FechTest .java

package cn.itcast.hibernate;
import org.hibernate.Session;
import junit.framework.TestCase;
public class FechTest extends TestCase {

    public void testFetch1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Student student = (Student)session.load(Student.class, 1);
            System.out.println("student.name=" + student.getName());
            System.out.println("classes.name=" + student.getClasses().getName());
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

說明:可以看到在運行此程序時會發(fā)出兩條sql語句分別去查詢學(xué)生名字和班級名字拳氢。

2.2使用join策略(工程hibernate_fetch_2

Student.hbm.xml中進行配置:
<many-to-one name="classes" column="classesid" fetch="join"/>

測試:
FechTest .java

package cn.itcast.hibernate;
import org.hibernate.Session;
import junit.framework.TestCase;
public class FechTest extends TestCase {

    public void testFetch1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Student student = (Student)session.load(Student.class, 1);
            System.out.println("student.name=" + student.getName());
            System.out.println("classes.name=" + student.getClasses().getName());
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

說明:這里就只會發(fā)出一條sql語句,使用一個外連接將學(xué)生和班級都查詢出來了晓猛,當(dāng)然lazy就相當(dāng)于失效了饿幅。

三、集合代理的批量抓取

3.1使用默認(rèn)策略(工程hibernate_fetch_3

Classes.hbm.xml中:<set name="students" inverse="true" cascade="all" fetch="select">表示支持lazy戒职,會發(fā)出兩次sql語句去查詢栗恩。

測試:
FechTest.java

package cn.itcast.hibernate;
import java.util.Iterator;
import org.hibernate.Session;
import junit.framework.TestCase;
public class FechTest extends TestCase {

    public void testFetch1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            Classes classes = (Classes)session.load(Classes.class, 1);
            System.out.println("classes.name=" + classes.getName());
            for (Iterator iter=classes.getStudents().iterator(); iter.hasNext();) {
                Student student = (Student)iter.next();
                System.out.println("student.name=" + student.getName());
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

說明:同樣在默認(rèn)情況下是支持lazy的,會發(fā)出兩次sql語句查詢洪燥。

3.2使用join策略(工程hibernate_fetch_4

Classes.hbm.xml中:<set name="students" inverse="true" cascade="all" fetch="join">
表示在發(fā)出第一條語句的時候就會將關(guān)聯(lián)的實體對象查出來磕秤,之后將不再發(fā)出sql去查詢關(guān)聯(lián)的實體對象。

測試的例子和上面一樣捧韵。同樣使用join策略就不會再次發(fā)出sql語句了市咆。

3.3使用subselect策略(工程hibernate_fetch_5

Classes.hbm.xml中:
<set name="students" inverse="true" cascade="all" fetch="subselect">
如果默認(rèn)需要查詢?nèi)齻€關(guān)聯(lián)實體對象則在默認(rèn)情況下會發(fā)出三條sql語句去查詢關(guān)聯(lián)對象,但是如果設(shè)置了subselect則只會發(fā)出一條sql語句將三個實體對象都查出來再来。

測試使用的例子和上面一樣蒙兰。而實際運行結(jié)果和默認(rèn)的select策略是一樣的磷瘤,沒有什么不同。但是這種策略會影響hql查詢搜变,看下面的測試用例:

/**
     * Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, 
     * students0_.id as id1_0_, students0_.name as name1_0_, 
     * students0_.classesid as classesid1_0_ 
     * from t_student students0_ 
     * where students0_.classesid in (select classes0_.id from t_classes classes0_ where classes0_.id in (1 , 2 , 3))
     */
    public void testFetch2() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            List classesList = session.createQuery("select c from Classes c where c.id in(1, 2, 3)").list();
            for (Iterator iter=classesList.iterator(); iter.hasNext();) {
                Classes classes = (Classes)iter.next();
                System.out.println("classes.name=" + classes.getName());
                for (Iterator iter1=classes.getStudents().iterator(); iter1.hasNext();) {
                    Student student = (Student)iter1.next();
                    System.out.println("student.name=" + student.getName());
                }
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }

說明:如果抓取策略是默認(rèn)的采缚,先發(fā)出一條sql語句查詢出班級,然后再根據(jù)id依次發(fā)出3條sql語句去查班級里面的學(xué)生挠他。當(dāng)使用subselect策略時扳抽,也是先發(fā)出一條sql語句查詢出班級,但是之后則只會發(fā)出一條sql語句將前面查詢到的班級中的學(xué)生都查詢出來殖侵。

四贸呢、抓取策略中的批量操作

4.1在實體類中使用(工程hibernate_fetch_6

Classes.hbm.xml中:
<class name="cn.itcast.hibernate.Classes" table="t_classes" batch-size="5">這里設(shè)置批量操作值為5,表示每次查詢5條結(jié)果集拢军。

測試:
FechTest .java

package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import junit.framework.TestCase;

public class FechTest extends TestCase {

    public void testFetch1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            List students = session.createQuery("select s from Student s where s.id in(:ids)")
                   .setParameterList("ids", new Object[]{1, 11, 21, 31, 41, 51, 61, 71, 81, 91})
                   .list();
            for (Iterator iter=students.iterator(); iter.hasNext();) {
                Student  student = (Student)iter.next();
                System.out.println("student.name=" + student.getName());
                System.out.println("classes.name=" + student.getClasses().getName());
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

說明:默認(rèn)是首先發(fā)出sql去查詢學(xué)生楞陷,然后一次發(fā)出多條sql分別查詢每個學(xué)生的班級,如果我們使用批量操作茉唉,那么會一次查詢多條數(shù)據(jù)猜谚,比如這里設(shè)置批量值為5,那么查詢10個學(xué)生的班級赌渣,那么只會發(fā)出兩條sql而不是默認(rèn)的10條魏铅。

4.2在集合中使用(工程hibernate_fetch_7

Classes.hbm.xml中:
<set name="students" inverse="true" cascade="all" batch-size="5">這里設(shè)置批量操作值為5,表示每次查詢5條結(jié)果集坚芜。

測試:
FechTest .java

package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import junit.framework.TestCase;
public class FechTest extends TestCase {

    public void testFetch1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            List classesList = session.createQuery("select c from Classes c").list();
            for (Iterator iter=classesList.iterator(); iter.hasNext();) {
                Classes classes = (Classes)iter.next();
                System.out.println("classes.name=" + classes.getName());
                for (Iterator iter1=classes.getStudents().iterator(); iter1.hasNext();) {
                    Student student = (Student)iter1.next();
                    System.out.println("student.name=" + student.getName());
                }
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }       
    }   
}

說明:本來默認(rèn)是發(fā)出N條sql語句查詢的览芳,但是這里我們設(shè)置了集合的批量操作,那么每次就會查詢出多條記錄鸿竖,發(fā)出的sql語句也就相應(yīng)的減少沧竟。

五、批量更新

  • jdbc fetch size
    每次取多少數(shù)據(jù)缚忧,需要jdbc和底層數(shù)據(jù)庫的支持悟泵。不會一次性把全部數(shù)據(jù)讀入內(nèi)存,而是按照一定的數(shù)量來批量讀取相應(yīng)的數(shù)據(jù)闪水。建議值是50糕非,在hibernate.cfg.xml中:
    <property name="hibernate.jdbc.fetch_size">50</property>

  • jdbc batch size
    批量更新,建議取值為30球榆,在hibernate.cfg.xml中:
    <property name="hibernate.jdbc.batch_size">30</property>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末朽肥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子持钉,更是在濱河造成了極大的恐慌衡招,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件每强,死亡現(xiàn)場離奇詭異始腾,居然都是意外死亡州刽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門浪箭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怀伦,“玉大人,你說我怎么就攤上這事山林。” “怎么了邢羔?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵驼抹,是天一觀的道長。 經(jīng)常有香客問我拜鹤,道長框冀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任敏簿,我火速辦了婚禮明也,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惯裕。我一直安慰自己温数,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布蜻势。 她就那樣靜靜地躺著撑刺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪握玛。 梳的紋絲不亂的頭發(fā)上够傍,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音挠铲,去河邊找鬼冕屯。 笑死,一個胖子當(dāng)著我的面吹牛拂苹,可吹牛的內(nèi)容都是我干的安聘。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼瓢棒,長吁一口氣:“原來是場噩夢啊……” “哼搞挣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起音羞,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤囱桨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嗅绰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舍肠,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡搀继,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了翠语。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叽躯。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肌括,靈堂內(nèi)的尸體忽然破棺而出点骑,到底是詐尸還是另有隱情,我是刑警寧澤谍夭,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布黑滴,位于F島的核電站,受9級特大地震影響紧索,放射性物質(zhì)發(fā)生泄漏袁辈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一珠漂、第九天 我趴在偏房一處隱蔽的房頂上張望晚缩。 院中可真熱鬧,春花似錦媳危、人聲如沸荞彼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卿泽。三九已至,卻和暖如春滋觉,著一層夾襖步出監(jiān)牢的瞬間签夭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工椎侠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留第租,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓我纪,卻偏偏與公主長得像慎宾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浅悉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

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

  • 延遲加載和急加載 有些時候,必須決定應(yīng)該講那些數(shù)據(jù)從數(shù)據(jù)庫中加載到內(nèi)存中,當(dāng)執(zhí)行entityManager.fin...
    Captain_w閱讀 644評論 0 0
  • 一趟据、簡介 延遲加載就是我們真正使用某個對象的時候,這個對象才會被創(chuàng)建出來术健。而在hibernate中的意思就是只有我...
    yjaal閱讀 602評論 0 0
  • Defining the global fetch plan Retrieving persistent obje...
    ilaoke閱讀 5,517評論 1 6
  • Hibernate: 一個持久化框架 一個ORM框架 加載:根據(jù)特定的OID,把一個對象從數(shù)據(jù)庫加載到內(nèi)存中OID...
    JHMichael閱讀 1,963評論 0 27
  • Hibernate中配置主要分為兩種:一種包含了Hibernate與數(shù)據(jù)庫的基本連接信息汹碱,在Hibernate工作...
    FTOLsXD閱讀 2,032評論 0 10