性能分析
抓取策略
研究对象
研究怎么样提取集合,该策略应该作用于set元上
研究从少的一方加载多的一方
案例
查询id为1 的班级所有的学生
|
|
Classes中的set节点:
执行上述的代码,在fetch=”join”的配置下,hibernate执行如下的SQL语句:
说明: 通过一条SQL语句:做外连接,把classes与student表的数据全部提取出来。
如果是如下的策略:
先查询classes,再查询student如下图:
查询所有的班级的所有的学生
|
|
该需求翻译过来含有子查询
select s.* from student s where s.cid in(select cid from classes)
如果含有子查询,必须用subselect
改进:
将Classes配置文件中的set节点配置成如上后,hibernate输出如下的SQL信息:
!fetch=subselect
查询班级为1,2,3,4的所有的学生
Classes配置文件中的set节点:
|
|
总结
- 研究对象是集合。
- 经过分析,如果SQL语句中包含有了子查询,则用subselect效率比较高。
- 如果页面上需要一次性把两张表的数据全部提取出来,用join效率比较高。
- 如果select,先查询学生,如果查询班级的个数超过1个,会导致n + 1条SQL语句。
- 抓取策略是hibernate提供的一种优化方式而已。
延迟加载(懒加载)
概念
需要用到数据的时候才要加载。延迟加载的优化措施是优化SQL语句的发出时间。
种类
类的延迟加载
|
|
hibernate执行的SQL的输出:
说明:
- 执行第一条输出classes.getCid()的时候,不发出SQL语句,说明类的延迟加载和主键没有关系。
- 执行第二条输出classes.getName()的时候,发出了SQL语句,说明在得到了具体的属性的时候才要发出SQL语句。
3.Session.load()方法返回的时候,返回的对象是classes=Classes_$$_javassist_1
,是一个代理对象,而该对象是由javassist的jar包生成的,从代码结构可以看出该代理对象是持久化类的子类。- 在Classes.hbm.xml文件中
<class nam="com.wcc.hibernate.domain.Classes" lazy="true">
<!--lzay的属性默认是true-->
- 如果把上述的lazy改成false,则类的延迟加载不起作用了,默认为延迟加载。
集合的延迟加载
案例一
说明:
1.lazy的取值有三种情况:extra、false、true。
- 默认情况下,lazy属性的默认值是true, 此时,集合的延迟加载只有在遍历集合的时候才会发出SQL语句
- lazy的值为false,当加载classes的时候就把student加载出来了
- lazy的值是Extra:是更进一步延迟加载策略,如果求大小,平均数、和等。
案例二
当上述代码中在lazy=”true”的情况下运行的时候,执行set.size()的时候,会执行查询语句,但是我们只需要的是集合的size,当lazy=”extra”时,表示的是更进一步的延迟加载,需要什么就加载什么,当执行到上述的student.size() 的时候,发出如下的SQL语句:
该SQL语句只加载了大小,并没有加载具体的数据。
Many-to-one的延迟加载
总结
延迟加载是通过什么时候加载SQL语句来优化性能的
抓取策略和延迟加载的结合
研究对象
set集合
- 当fetch为join时,lazy失效。
- 当fetch为select时
- 如果lazy为true/extra,当遍历集合的时候,发出加载集合的SQL语句,如果lazy为false,当获取班级的时候,发出加载集合的SQL语句
- 当fetch为subselect时和上面的情况一致。
二级缓存
概念
- 是sessionFactory级别的缓存
- 存放的是公有数据:共享数据
- 二级缓存的生命周期是随着hibernate容器启动就开了,hibernate销毁,结束。
- hibernate本身对二级缓存没有提供实现,是借助第三方插件实现的。
特点
公有数据的特征:
- 一般情况下保持不变
- 所有的人都能访问
- 访问的频率比较高
- 安全性不是特别高的数据
配置
在hibernate的配置文件中
12345678<!-- 开启 二级缓存 --><property name="cache.use_second_level_cache">true</property><!-- 二级缓存的供应商 --><property name="cache_provider_class">org.hibernate.cache.EhCacheProvider</property><!-- 开启hibernate 的统计机制 --><property name="hibernate.generate_statistics">true</property>二级缓存分为类的二级缓存和集合的二级缓存
- 开启哪个类的二级缓存就是在哪一个类的映射文件中进行二级缓存的配置。例如在classes类中进行二级缓存1234<class name="com.wcc.hibernate.domain.Classes"><!--在class中增加cache结点--><cache usage="read-only"/></class>
案例
案例一
|
|
说明: 当第二次执行session.get()方法的时候,并没有发出SQL语句。 Session.save(),Session.update(),方法不能让一个对象进入到二级缓存中。
案例二
|
|
说明:
1.执行List<Classes> classes = session.createQuery("from Classes").list();
代码的时候,把classes表中的所有的对象进入到了二级缓存中。
- 执行
List<Classes> classes1 = session.createQuery("from classes where cid in(1, 2)").list();
的时候,重新从数据库中查找记录。- 所以createQuery(hql).list();方法能把一个对象放入二级缓存中,但是不利于二级缓存获取对象。
案例三 硬盘缓存
|
|
从上面的配置可以看出,classes对象在内存中存放的数量最多为3个,多余的对象将存在磁盘上。
|
|
上面相当于开启了classes类中的set集合的二级缓存。
读写策略
Usage
- Ready-only :只能把一个对象放入到二级缓存中,不能修改。
- Read-write :能把一个对象放入到二级缓存中,也能修改。