zoukankan      html  css  js  c++  java
  • hibernate查漏补缺3

    hibernate的检索策略

    转载请注明: TheViper http://www.cnblogs.com/TheViper

    先看个大概

     

     

     1.类级别

    立即检索 <class lazy='false'>;延迟检索 <class lazy='true'>.默认为延迟检索。

    如果加载一个持久化对象是为了获取它的属性,用立即检索;而如果仅仅是为了获取它的引用,用延迟加载。比如,

        Friend_Category fc = new Friend_Category();
            fc.setCategory_name("已经存在的好友分类");
            User_Friend_pk pk = new User_Friend_pk();
            pk.setFriend_name(“新好友”);
            pk.setName("TheViper");
            User_Friend uf = new User_Friend();
            uf.setUser_friend_pk(pk);
            Friend_Category fc1 = (Friend_Category) session.load(
                    Friend_Category.class, 1);
            uf.setFriend_categorys(fc1);
    
            // uf.setSort("好基友");
            session.saveOrUpdate(fc1);
            session.save(uf);

    可以看到,加载Friend_Catagory类只是为了把新加好友加入到已经存在的好友分类里。这里用load()返回一个代理类,里面只有id属性,其他属性均为null,并没有返回所有的属性,因此占用的内存很少。

     另外,不管<class> 的lazy属性是true还是false,get(),list()总是用立即加载,但是并不会去加载与之相关联的类(关联级别检索为默认设置延迟加载)。

     2.关联级别

    •  一对多和多对多关联的检索策略

    由<set>的lazy和fetch属性决定

    lazy:决定关联集合被初始化的时机。即是在加载时就被初始化,还是在被访问时才初始化。

    fetch:取值为select或subselect时,决定初始化关联集合时查询语句的形式;取值为fetch时,决定关联集合被初始化的时机,这时显式设置lazy属性是无意义的。

     lazy=true时,关联集合类的代理在下面情况会被初始化:

    1.应用程序第一次访问它,如调用它的iterator(),size(),isEmpty()或contains().

    2.通过org.hibernate.Hibernate类的initialize()静态方法初始化。

    对于lazy=extra,hibernate会进一步延迟关联对象的初始化时机。具体说就是仅当应用程序第一次调用关联对象的iterator()时才会加载。只有这一个方法能起作用。

    对于lazy=false,

    Feeling f = (Feeling) session.get(Feeling.class, 1);
            <set name="feelingComments" inverse="true" lazy="false">
                <key column="feeling_id" />
                <one-to-many class="model.FeelingComment" />
            </set>

    当取出Feeling类时,便会一并取出FeelingComment类

    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_0_,
            feeling0_.content as content1_0_,
            feeling0_.id as id1_0_ 
        from
            feeling feeling0_ 
        where
            feeling0_.feeling_id =?
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?

     下面设置fetch=subselect,

            Session session = sf.openSession();
            Transaction transaction = session.beginTransaction();
            Query q = session.createQuery("from Feeling feeling");
            List<Feeling> feelings = (List<Feeling>) q.list();
            for (Feeling feeling : feelings) {
                Set comments = feeling.getFeelingComments();
                System.out.println(comments);
            }
            transaction.commit();
            session.close();
    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_,
            feeling0_.content as content1_,
            feeling0_.id as id1_ 
        from
            feeling feeling0_
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id in (
                select
                    feeling0_.feeling_id  
                from
                    feeling feeling0_
            )
    [model.FeelingComment@17f2fe3, model.FeelingComment@1211a4b, model.FeelingComment@533fc3]
    [model.FeelingComment@a9a994, model.FeelingComment@455d96]
    [model.FeelingComment@35c6f]

    可以看到hibernate是用in子查询的方式抓取关联对象的,这时batch-size属性会被忽略。

    fetch=join表示采用左外连接的检索策略抓取关联对象,注意list()会自动忽略这个设置,这个很重要。

    还是上面的代码,结果

    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_,
            feeling0_.content as content1_,
            feeling0_.id as id1_ 
        from
            feeling feeling0_
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?
    [model.FeelingComment@1fbf047, model.FeelingComment@82a092, model.FeelingComment@15bd7c5]
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?
    [model.FeelingComment@c407e, model.FeelingComment@5e3212]
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?
    [model.FeelingComment@69757f]

     而这时设置lazy,batch-size属性没有意义。

     关于batch-size属性,它用来为检索策略设定批量检索的数量,可以减少select语句的数量,提供检索的运行性能。

    比如batch-size设为2,关联集合里面有3个对象。

            Session session = sf.openSession();
            Transaction transaction = session.beginTransaction();
            Query q = session.createQuery("from Feeling feeling");
            List<Feeling> feelings = (List<Feeling>) q.list();
            for (Feeling feeling : feelings) {
                Set comments = feeling.getFeelingComments();
                System.out.println(comments);
            }
            transaction.commit();
            session.close();
    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_,
            feeling0_.content as content1_,
            feeling0_.id as id1_ 
        from
            feeling feeling0_
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id in (
                ?, ?
            )
    [model.FeelingComment@177151, model.FeelingComment@16e125, model.FeelingComment@110a0ca]
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?
    [model.FeelingComment@1c8f247, model.FeelingComment@1d67998]
    [model.FeelingComment@ac44e3]

    注意,如果对Query接口用iterator()返回数据的话,会忽略batch-size!

    Hibernate: 
        select
            feeling0_.feeling_id  as col_0_0_ 
        from
            feeling feeling0_
    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_0_,
            feeling0_.content as content1_0_,
            feeling0_.id as id1_0_ 
        from
            feeling feeling0_ 
        where
            feeling0_.feeling_id =?
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?
    [model.FeelingComment@ee7d2a, model.FeelingComment@fb3758, model.FeelingComment@17596bc]
    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_0_,
            feeling0_.content as content1_0_,
            feeling0_.id as id1_0_ 
        from
            feeling feeling0_ 
        where
            feeling0_.feeling_id =?
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?
    [model.FeelingComment@855e17]
    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_0_,
            feeling0_.content as content1_0_,
            feeling0_.id as id1_0_ 
        from
            feeling feeling0_ 
        where
            feeling0_.feeling_id =?
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?
    [model.FeelingComment@85ba73, model.FeelingComment@191bae7]

    iterator()参见上一篇说明.

    •  多对一和一对一关联的检索策略

     

    fetch=join

            <set name="feelingComments" inverse="true">
                <key column="feeling_id" />
                <one-to-many class="model.FeelingComment" />
            </set>
            <many-to-one name="feelings" column="feeling_id" class="model.Feeling"
                not-null="false" fetch="join">
            </many-to-one>
            FeelingComment f = (FeelingComment) session
                    .get(FeelingComment.class, 1);
    Hibernate: 
        select
            feelingcom0_.feelingComment_id  as feelingC1_2_1_,
            feelingcom0_.content as content2_1_,
            feelingcom0_.feeling_id as feeling3_2_1_,
            feelingcom0_.id as id2_1_,
            feeling1_.feeling_id  as feeling1_1_0_,
            feeling1_.content as content1_0_,
            feeling1_.id as id1_0_ 
        from
            feeling_comment feelingcom0_ 
        left outer join
            feeling feeling1_ 
                on feelingcom0_.feeling_id=feeling1_.feeling_id  
        where
            feelingcom0_.feelingComment_id =?

    上面的很简单。稍微变一下,在<set>添加lazy=false.

    Hibernate: 
        select
            feelingcom0_.feelingComment_id  as feelingC1_2_1_,
            feelingcom0_.content as content2_1_,
            feelingcom0_.feeling_id as feeling3_2_1_,
            feelingcom0_.id as id2_1_,
            feeling1_.feeling_id  as feeling1_1_0_,
            feeling1_.content as content1_0_,
            feeling1_.id as id1_0_ 
        from
            feeling_comment feelingcom0_ 
        left outer join
            feeling feeling1_ 
                on feelingcom0_.feeling_id=feeling1_.feeling_id  
        where
            feelingcom0_.feelingComment_id =?
    Hibernate: 
        select
            feelingcom0_.feeling_id as feeling3_1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_1_,
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feeling_id=?

    可以看到,这次发出了两条sql,第二次会再次根据feeling_id取出feeling_comment,个人感觉没意义啊。而在一对多和多对多中就不会出现这种情况。

    另外,list()也会像一对多和多对多,忽略fetch=join.

    lazy=proxy(默认)

    这个像一对多和多对多里面的lazy=true.即查询“多”那边时,不会查询“一”那边的关联对象。只有当实际要用关联对象时才会初始化它。

    注意对于<one-to-one>,必须要设置constrained=true.表明“一”那边的关联对象不能为空。

    lazy=no-proxy

    这个和lazy=proxy很相似。不过需要编译时字节码增强,否则和proxy没区别 。

    这样做了后的效果。

            FeelingComment f = (FeelingComment) session
                    .get(FeelingComment.class, 1);
            Feeling f1 = f.getFeelings();
            f1.getContent();

    当运行到getFeelings()时,hibernate会发出sql.而lazy=proxy时,要运行到getContent()时才发出。

    lazy=false

    当运行到get()时就会发出两条sql.

    Hibernate: 
        select
            feelingcom0_.feelingComment_id  as feelingC1_2_0_,
            feelingcom0_.content as content2_0_,
            feelingcom0_.feeling_id as feeling3_2_0_,
            feelingcom0_.id as id2_0_ 
        from
            feeling_comment feelingcom0_ 
        where
            feelingcom0_.feelingComment_id =?
    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_0_,
            feeling0_.content as content1_0_,
            feeling0_.id as id1_0_ 
        from
            feeling feeling0_ 
        where
            feeling0_.feeling_id =?

    另外如果

            <many-to-one name="feelings" column="feeling_id" class="model.Feeling"
                not-null="false" lazy="false">

    同时在“一”那边

        <class name="model.Feeling" table="feeling" lazy="false">
        </class>

    便会出现和fetch=join一样的sql.

            FeelingComment f = (FeelingComment) session
                    .get(FeelingComment.class, 1);
    Hibernate: 
        select
            feelingcom0_.feelingComment_id  as feelingC1_2_1_,
            feelingcom0_.content as content2_1_,
            feelingcom0_.feeling_id as feeling3_2_1_,
            feelingcom0_.id as id2_1_,
            feeling1_.feeling_id  as feeling1_1_0_,
            feeling1_.content as content1_0_,
            feeling1_.id as id1_0_ 
        from
            feeling_comment feelingcom0_ 
        left outer join
            feeling feeling1_ 
                on feelingcom0_.feeling_id=feeling1_.feeling_id  
        where
            feelingcom0_.feelingComment_id =?

    在多对一和一对一中使用批量检索

    在<many-to-one>,<one-to-one>中没有batch-size属性,需要“一”那边设置batch-size.比如,需要加装三个关联实例(一),batch-size=2.

        <class name="model.Feeling" table="feeling" batch-size="2">
        </class>
            Query q = session.createQuery("from FeelingComment");
            List<FeelingComment> feelings = (List<FeelingComment>) q.list();
            for (FeelingComment feelingComment : feelings) {
                Feeling feeling = feelingComment.getFeelings();
                System.out.println(feeling);
            }
    Hibernate: 
        select
            feelingcom0_.feelingComment_id  as feelingC1_2_,
            feelingcom0_.content as content2_,
            feelingcom0_.feeling_id as feeling3_2_,
            feelingcom0_.id as id2_ 
        from
            feeling_comment feelingcom0_
    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_0_,
            feeling0_.content as content1_0_,
            feeling0_.id as id1_0_ 
        from
            feeling feeling0_ 
        where
            feeling0_.feeling_id  in (
                ?, ?
            )
    model.Feeling@1e684bd
    model.Feeling@1e684bd
    model.Feeling@1e684bd
    model.Feeling@1149b6c
    Hibernate: 
        select
            feeling0_.feeling_id  as feeling1_1_0_,
            feeling0_.content as content1_0_,
            feeling0_.id as id1_0_ 
        from
            feeling feeling0_ 
        where
            feeling0_.feeling_id =?
    model.Feeling@fb8996
    model.Feeling@1149b6c

    注意上面的例子<many-to-one>中的lazy是默认的proxy.如果lazy=false的话,当运行到feelingComment.getFeelings();时就会发出后面的sql了。

    • 属性级别的检索策略

    只需在<property>,<component>上设置lazy=true.这种策略适用于二进制大对象,字符串大对象,大容量组件类型的属性。比如User类的image属性储存着图片的二进制数据,

    User user=(User)session.get(User.class,1);user.getImage();

    get()时,hibernate没有加载image属性,运行到getImage()时才会加载。

     注意,用的时候必须向多对一,一对一lazy=no-proxy一样,需要编译时字节码增强。

  • 相关阅读:
    1.Spring MVC详解
    servlet的九大内置对象
    Hibernate设置事务的隔离级别
    wamp下php报错session_start(): open(d:/wamp/tmpsess_ku776hvb06ko4lv9d11e7mnfj1, O_RDWR) failed: No such file or directory
    json_decode()相关报错
    wamp下var_dump()相关问题
    es6箭头函数内部判断
    Json数组对象取值
    npm指向淘宝源
    APICloud之封装webApp
  • 原文地址:https://www.cnblogs.com/TheViper/p/4116377.html
Copyright © 2011-2022 走看看