Home >Database >Mysql Tutorial >Hibernate的关联关系中lazy和fetch的设置

Hibernate的关联关系中lazy和fetch的设置

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOriginal
2016-06-07 17:10:05874browse

Hibernate的关联关系中lazy和fetch的设置会影响到对数据进行查询时候SQL语句的操作,fetch的设置相对于lazy的优先级更高,而且在cl

Hibernate的关联关系中lazy和fetch的设置会影响到对数据进行查询时候SQL语句的操作,fetch的设置相对于lazy的优先级更高,而且在class标签上配置的lazy属性不会影响到关联对象.(本例用的版本是Hibernate3)

本例假设有一个主表为MASTTB,有一个子表为DETAILTB.

主表端的fetch可以取 'join','select'和'subselect'(select为默认值):

join:外连接一次查询.

select:1+n 条select语句,第一条查主表,第n条查第n条主表记录对应的子表记录.

subselect: 以 id in(...)的方式做第二条查询,(如果查询主表的是返回单条记录,subselect和select没有区别,如果查询主表的是返回多条记录的话,对子表查询会以id in 的方式).具体见例4.

lazy可以取'true','extra'以及 'false'(true为默认值):

true:默认取值,它的意思是只有在调用这个集合获取里面的元素对象时,才发出查询语句,加载其集合元素的数据.
false:取消延迟加载特性,即在加载对象的同时,就发出第二条查询语句加载其关联集合的数据.
extra:一种比较聪明的延迟加载策略,即调用集合的size/contains等方法的时候,hibernate并不会去加载整个集合的数据,而是发出一条"聪明"的SQL语句,以便获得需要的值,只有在真正需要用到这些集合元素对象数据的时候,才去发出查询语句加载所有对象的数据.
比如看集合的size:

会发出下面的SQL语句

    select
        count(DTID)
    from
        DETAILTB
    where
        MTID =?


1,对主表进行findById查询的测试,当fetch设为join的时候, 不管lazy是true还是false,都是一次以主表左外连接子表的方式把关联的数据全部查出来.SQL如下:

    select
        masttb0_.MID as MID1_1_,
        masttb0_.MASTINFO as MASTINFO1_1_,
        detailtbs1_.MTID as MTID3_,
        detailtbs1_.DTID as DTID3_,
        detailtbs1_.DTID as DTID2_0_,
        detailtbs1_.MTID as MTID2_0_,
        detailtbs1_.DETAILINFO as DETAILINFO2_0_
    from
        MASTTB masttb0_
    left outer join
        DETAILTB detailtbs1_
            on masttb0_.MID=detailtbs1_.MTID
    where
        masttb0_.MID=?

2,对主表进行findById查询的测试,当fetch设为select的时候,lazy 是true的时候,hibernate先用一条SQL将主表的数据查出来,然后在取子表数据的时候(在访问set的iterator的时候),再以子表的外键作为条件,用SQL语句取子表的数据.
JAVA代码如下:
            tx = sessionFactory.getCurrentSession().beginTransaction();
            MasttbHome masttbHome = new MasttbHome();
          
            Masttb masttb  = masttbHome.findById(new BigDecimal(1));
            System.out.println("before getting detai set");
          
            Set set = masttb.getDetailtbs();
          
            System.out.println("after getting detai set");
            Iterator itr = set.iterator();
            System.out.println("after getting detai set iterator");
            while(itr.hasNext()){
                Detailtb detailtb = (Detailtb)itr.next();
                System.out.println("after getting detai info " + detailtb.getDtid());
            }

            tx.commit();
运行结果如下:
Hibernate:
    select
        masttb0_.MID as MID1_0_,
        masttb0_.MASTINFO as MASTINFO1_0_
    from
        MASTTB masttb0_
    where
        masttb0_.MID=?
before getting detai set
after getting detai set
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID=?
after getting detai set iterator
after getting detai info 2
after getting detai info 1

3,对主表进行findById查询的测试,当fetch设为select的时候,lazy是false的时候,hibernate先用一条SQL将主表的数据查出来,然后马上再以子表的外键作为条件,用SQL语句取子表的数据.
上面例2的代码会打印:
Hibernate:
    select
        masttb0_.MID as MID1_0_,
        masttb0_.MASTINFO as MASTINFO1_0_
    from
        MASTTB masttb0_
    where
        masttb0_.MID=?
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID=?
before getting detai set
after getting detai set
after getting detai set iterator
after getting detai info 2
after getting detai info 1


*如果将lazy设为true,fetch设为 select,在session关闭后在去访问set里的值,会出异常.
 org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.hb.Masttb.detailtbs, no session or session was closed

 

4,对主表进行多条记录查询的测试,当fetch设为subselect的时候,lazy是true的时候,hibernate先用一条SQL将主表的数据查出来,然后用id in 方式的SQL语句取子表的数据.

JAVA代码:

            tx = sessionFactory.getCurrentSession().beginTransaction();
           
            List mstlist = sessionFactory.getCurrentSession().createQuery("from com.test.hb.Masttb where id in (1,2)").list();

            //下面的hql和上面的hql有同样的效果

           //List mstlist = sessionFactory.getCurrentSession().createQuery("from com.test.hb.Masttb where id             for (Iterator iter = mstlist.iterator(); iter.hasNext();) {
                Masttb masttb = (Masttb) iter.next();
                System.out.println("masttb.getMastinfo=" + masttb.getMastinfo());
                Set set = masttb.getDetailtbs();
                System.out.println(set.size());
                if (set != null && !set.isEmpty()) {
                    for (Iterator itr = set.iterator(); itr.hasNext();) {
                        Detailtb detailtb = (Detailtb) itr.next();
                        System.out.println("detailtb.name=" + detailtb.getDetailinfo());
                    }
                }
            }

            tx.commit();

运行结果:

Hibernate:
    select
        masttb0_.MID as MID1_,
        masttb0_.MASTINFO as MASTINFO1_
    from
        MASTTB masttb0_
    where
        masttb0_.MID in (
            1 , 2
        )
masttb.getMastinfo=mastinfo
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID in (
            select
                masttb0_.MID
            from
                MASTTB masttb0_
            where
                masttb0_.MID in (
                    1 , 2
                )
        )
number in detail table: 2
detailtb.name=aaaa
detailtb.name=detailinfo2
masttb.getMastinfo=aaa
number in detail table: 1
detailtb.name=adfasdfa

如果fetch=select,lazy=true的话,运行结果为 1 + 2条SQL语句:

Hibernate:
    select
        masttb0_.MID as MID1_,
        masttb0_.MASTINFO as MASTINFO1_
    from
        MASTTB masttb0_
    where
        masttb0_.MID in (
            1 , 2
        )
masttb.getMastinfo=mastinfo
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID=?
number in detail table: 2
detailtb.name=aaaa
detailtb.name=detailinfo2
masttb.getMastinfo=aaa
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID=?
number in detail table: 1
detailtb.name=adfasdfa

linux

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn