Hibernate(四)

16 篇文章 0 订阅
5 篇文章 0 订阅

抓取策略

案例一

<!--默认值为”select” -->
<set name="students" lazy="true" fetch="select">
/**
     * 发出两条sql语句
     */
    @Test
    public void testSetFetch_Select(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Classes classes = (Classes)session.get(Classes.class, 1L);
        Set<Student> students = classes.getStudents();
        for(Student student:students){
            System.out.println(student.getName());
        }
        transaction.commit();
    }

fetch_select

上述的图中会发出n+1条sql语句,1代表查询classes表的数据,n代表classes表中的记录数

Hibernate: 
    select
        classes0_.cid as cid0_0_,
        classes0_.name as name0_0_ 
    from
        Classes classes0_ 
    where
        classes0_.cid=?
Hibernate: 
    select
        students0_.cid as cid0_1_,
        students0_.sid as sid1_,
        students0_.sid as sid1_0_,
        students0_.name as name1_0_,
        students0_.cid as cid1_0_ 
    from
        Student students0_ 
    where
        students0_.cid=?

案例二

<set name="students" lazy="true" fetch="join">
Hibernate: 
    select
        classes0_.cid as cid0_1_,
        classes0_.name as name0_1_,
        students1_.cid as cid0_3_,
        students1_.sid as sid3_,
        students1_.sid as sid1_0_,
        students1_.name as name1_0_,
        students1_.cid as cid1_0_ 
    from
        Classes classes0_ 
    left outer join
        Student students1_ 
            on classes0_.cid=students1_.cid 
    where
        classes0_.cid=?

案例三

<set name="students" lazy="true" fetch="subselect">
/**
     *  查询所有的班级的所有的学生
     */
    @Test
    public void testSubSelect(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        List<Classes> classesList = session.createQuery("from Classes").list();
        for(Classes classes:classesList){
            Set<Student> students = classes.getStudents();
            for(Student student:students){
                System.out.println(student.getName());
            }
        }
        transaction.commit();
    }
Hibernate: 
    select
        classes0_.cid as cid0_,
        classes0_.name as name0_ 
    from
        Classes classes0_
Hibernate: 
    select
        students0_.cid as cid0_1_,
        students0_.sid as sid1_,
        students0_.sid as sid1_0_,
        students0_.name as name1_0_,
        students0_.cid as cid1_0_ 
    from
        Student students0_ 
    where
        students0_.cid in (
            select
                classes0_.cid 
            from
                Classes classes0_
        )

案例四

/**
     * 查询cid为1,2,3的班级的信息和这些班级中学生的信息
     */
    @Test
    public void testSubSelect_2(){
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        List<Classes> classesList = session.createQuery("from Classes where cid in(1,2,3)").list();
        for(Classes classes:classesList){
            Set<Student> students = classes.getStudents();
            for(Student student:students){
                System.out.println(student.getName());
            }
        }
        transaction.commit();
    }
Hibernate: 
    select
        classes0_.cid as cid0_,
        classes0_.name as name0_ 
    from
        Classes classes0_ 
    where
        classes0_.cid in (
            1 , 2 , 3
        )
Hibernate: 
    select
        students0_.cid as cid0_1_,
        students0_.sid as sid1_,
        students0_.sid as sid1_0_,
        students0_.name as name1_0_,
        students0_.cid as cid1_0_ 
    from
        Student students0_ 
    where
        students0_.cid in (
            select
                classes0_.cid 
            from
                Classes classes0_ 
            where
                classes0_.cid in (
                    1 , 2 , 3
                )
        )

总结
需要一次性把数据全部查询出来,用join
如果经过需求分析翻译出来有子查询,用subselect
默认情况下用select
抓取策略的研究前提必须是关联对象,是研究怎么样发出sql语句来提取数据的
抓取策略只不过是hibernate给大家提供的一种优化策略而已。
因为抓取策略是写在映射文件中的,所以只能写一次。如果要想改变sql语句的结构,则用hql语句。
Subselect可以防止n+1条sql语句的出现

抓取策略和懒加载
1、研究对象为set集合
2、如果抓取策略为join,则懒加载失效
3、如果抓取策略为select,则保持懒加载的策略
4、如果抓取策略为subselect,则保持懒加载的策略

二级缓存
概念
1、为sessionFactory级别的缓存
2、二级缓存存放的是公共的数据
3、二级缓存的生命周期和sessionFactory的生命周期一样
4、二级缓存的存和取的策略

二级缓存

把数据存放到二级缓存中

Get方法

@Test
    public void testGet(){
        Session session = sessionFactory.openSession();
        Classes classes = (Classes)session.get(Classes.class, 2L);
        System.out.println(sessionFactory.getStatistics().getEntityLoadCount());
        session.close();
        session = sessionFactory.openSession();
        classes = (Classes)session.get(Classes.class, 2L);
        session.close();
    }
Hibernate: 
    select
        classes0_.cid as cid0_0_,
        classes0_.name as name0_0_ 
    from
        Classes classes0_ 
    where
        classes0_.cid=?

只发出了一条sql语句,第二个session.get方法的对象来自于二级缓存
2、当session执行save或者update方法的时候,没有必要放入到二级缓存中,因为修改的因素很大。

二级缓存的统计机制

<!-- 
        开启hibernate的统计机制
     -->
     <property name="hibernate.generate_statistics">true</property>

二级缓存的特点
一般情况下把一个对象放入到二级缓存中,对象的属性一般是不会改变的。

RW

RO

利用CacheModel控制二级缓存的对象
cacheModel

Hibernate: 
    select
        classes0_.cid as cid0_0_,
        classes0_.name as name0_0_ 
    from
        Classes classes0_ 
    where
        classes0_.cid=?
1
Hibernate: 
    update
        Classes 
    set
        name=? 
    where
        cid=?
222

二级缓存的磁盘化

<diskStore path="e:\\TEMP1"/>        
    <Cache
            name="cn.itcast.sh08.hibernate.domain.Classes"
            maxElementsInMemory="3" 
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />

二级缓存磁盘化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值