chho的专栏

对于整个世界我微不足道,但是我对于自己确是全部

用户操作
[即时聊天] [发私信] [加为好友]
常浩ID:chho
76182次访问,排名1315好友0人,关注者1
chho的文章
原创 106 篇
翻译 0 篇
转载 0 篇
评论 24 篇
chho的公告


名字:Chho
JAVA程序员,现在对Linux产生了浓厚的兴趣。

我的Mail:
最近评论
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 Hibernate入门24 - 延迟初始 Lazy Initialization收藏

    新一篇: Hibernate入门25 - Session 管理 | 旧一篇: Hibernate入门23 - 多对多实体映像

    入门 24 - 延迟初始 Lazy Initialization

     首先我们来看看这个主题:
    入门 11 - Set 映射
     依这个主题所完成的例子,请将Hibernate的show_sql设定为true,当我们使用下面的程序时,观看控制台所使用的SQL:

    HibernateTest.java

    import onlyfun.caterpillar.*;

    import net.sf.hibernate.*;

    import net.sf.hibernate.cfg.*;

    import java.util.*;

     

    public class HibernateTest {

        public static void main(String[] args) throws HibernateException {

            SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();

            Session session = sessionFactory.openSession();

          

            List users = session.find("from User");

     

            session.close();

            sessionFactory.close();

        }

    }


     SQL运作的例子如下:

    Hibernate: select user0_.USER_ID as USER_ID, user0_.NAME as NAME from USER user0_

    Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?

    Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?


     可以看到的,除了从USER表格中读取数据之外,还向ADDRS表格读取数据,预设上,Hibernate会将所有关联到的对象,透过一连串的SQL语 句读取并加载数据,然而现在考虑一种情况,我们只是要取得所有USER的名称,而不用取得它们的邮件地址,此时自动读取相关联的对象就是不必要的。
     在Hibernate中,集合类的映像可以延迟初始(Lazy Initialization),也就是在真正索取该对象的数据时,才向数据库查询,就这个例子来说,就是我们在读取User时,先不取得其中的 addrs属性中之对象数据,由于只需要读取User的name属性,此时我们只要执行一次select即可,真正需要addrs的数据时,才向数据库要 求。
     要使用Hibernate的延迟初始功能,只要在集合类映像时,加上lazy="true"即可,例如在我们的User.hbm.xml中的<set>中如下设定:

    User.hbm.xml

    <set name="addrs" table="ADDRS" lazy="true">

                <key column="USER_ID"/>

                <element type="string" column="ADDRESS" not-null="true"/>

            </set>


     我们来看看下面这个程序:

    HibernateTest.java

    import onlyfun.caterpillar.*;

    import net.sf.hibernate.*;

    import net.sf.hibernate.cfg.*;

    import java.util.*;

     

    public class HibernateTest {

        public static void main(String[] args) throws HibernateException {

            SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();

            Session session = sessionFactory.openSession();

          

            List users = session.find("from User");

     

            for (ListIterator iterator = users.listIterator(); iterator.hasNext(); ) {

                User user = (User) iterator.next();

                System.out.println(user.getName());

                Object[] addrs = user.getAddrs().toArray();

              

                for(int i = 0; i < addrs.length; i++) {

                    System.out.println("\taddress " + (i+1) + ": " + addrs[i]);  

                }

            }

     

            session.close();

            sessionFactory.close();

        }

    }


     在没有使用延迟初始时,控制台会显示以下的内容:

    Hibernate: select user0_.USER_ID as USER_ID, user0_.NAME as NAME from USER user0_

    Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?

    Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?

    caterpillar

       address 1: caterpillar@caterpillar.onlyfun.net

       address 2: justin@caterpillar.onlyfun.net

       address 3: justin@fake.com

    momor

       address 1: momor@fake.com

       address 2: momor@caterpillar.onlyfun.net


     如果使用延迟初始,则会出现以下的内容:

    Hibernate: select user0_.USER_ID as USER_ID, user0_.NAME as NAME from USER user0_

    caterpillar

    Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?

       address 1: caterpillar@caterpillar.onlyfun.net

       address 2: justin@caterpillar.onlyfun.net

       address 3: justin@fake.com

    momor

    Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?

       address 1: momor@fake.com

       address 2: momor@caterpillar.onlyfun.net


     请注意SQL语句出现的位置,在使用延迟初始功能前,会将所有相关联到的数据一次查完,而使用了延迟初始之后,只有在真正需要addrs的数据时,才会使用SQL查询相关数据。
     Hibernate实现延迟初始功能的方法,是藉由实现一个代理对象(以Set来说,其实现的代理子类是 net.sf.hibernate.collection.Set),这个代理类实现了其所代理之对象之相关方法,每个方法的实现实际上是委托(delegate)真正的对象,查询时加载的是代理对象,在真正呼叫对象的相关方法之前,不会去初始真正的对象来执行被呼叫的方法。
     所以为了能使用延迟初始,您在使用集合映像时,在宣告时必须是集合类的接口,而不是具体的实现类(例如宣告时使用Set,而不是HashSet)。
     使用延迟初始的一个问题是,由于在需要时才会去查询数据库,所以session不能关闭,如果在session关闭后,再去要求被关联的对象,将会发生LazyInitializationException,像是:

    Set addrs = user.getAddrs();

    session.close();

     

    // 下面这句会发生LazyInitializationException

    Object[] addrs = user.getAddrs().toArray();


     如果您使用了延迟初始,而在某些时候仍有需要在session关闭之后取得相关对象,则可以使用Hibernate.initialize()来先行加载相关对象,例如:

    Hibernate.initialize(user.getAddrs());    

    session.close();

    Set add = user.getAddrs();

    Object[] addo = user.getAddrs().toArray();


     延迟初始只是Hibernate在取得数据时的一种策略,目的是为了调节数据库存取时的时机以取得一些效能,除了延迟初始之外,还有其它的策略来调整资料库存取的方法与时机,这部份牵涉的讨论范围很大,有兴趣的话,可以参考Hibernate in Action的4.4.5。

    发表于 @ 2005年01月27日 20:42:00|编辑

    新一篇: Hibernate入门25 - Session 管理 | 旧一篇: Hibernate入门23 - 多对多实体映像

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © chho