性能分析
抓取策略
研究对象
研究怎么样提取集合的,该策略应该作用与set元素上
研究从一的一方加载多的一方
案例
查询cid为1的班级的所有的学生
明:通过一条sql语句:左外链接,把classes与student表的数据全部提取出来
查询所有的班级的所有的学生
该需求翻译过来含有子查询
如果含有子查询,必须用subselect
查询班级为1,2,3,4的所有的学生
抓取策略总结
1、 研究对象是集合
2、 经过分析,如果sql语句中含有了子查询,则用subselect效率比较高
3、 如果页面上需要一次性把两张表的数据全部提取出来,用join效率比较高
因为采用”join”为左外链接
4、 如果用select,先查询班级,后查询学生,如果查询班级的个数超过1个,会导致n+1条sql语句
5、 抓取策略是hibernate提供的一种优化方式而已
延迟加载
概念
需要用到该数据的时候才要加载
种类
类的延迟加载
案例
说明:
1、 执行22行代码的时候,不发出sql语句,说明类的延迟加载和主键没有关系
2、 执行23行代码的时候,发出sql语句,说明只有在得到具体属性的时候才要发出sql语句。
3、 Session.load方法返回的对象是
而该对象是由javassist的jar包生成的,从代码结构可以看出该代理对象是持久化类的子类。
4、 在Classes.hbm.xml文件中
Lazy的属性默认为true
5、如果把上述的lazy改成false,则类的延迟加载不起作用了,默认为延迟加载。
集合的延迟加载
案例一
值说明
默认情况是true,当遍历集合的时候发出sql语句
Lazy的值为false,当加载classes的时候就把student加载出来了
Extra是更进一步的延迟加载策略,如果求大小、平均数、和等
案例二
案例三
manytoone的延迟加载
No-proxy 延迟加载 默认值
Proxy是加强版的延迟加载
因为是通过多的一方加载一的一方,所以对效率影响不大,所以一般情况下用默认值即可
延迟加载总结:
延迟加载是通过什么时候发出sql语句来优化性能的。
抓取策略和延迟加载的结合
Set集合
1、 当fetch为join时,lazy失效
2、 当fetch为select时
如果lazy为true/extra
当遍历集合的时候,发出加载集合的sql语句
如果lazy为false
当获取班级的时候,发出加载集合的sql语句
3、 当fetch为subselect时和上面的情况一致。
二级缓存
概念:是sessionFactory级别的缓存
存放的是共有数据 共享数据
生命周期随着hibernate容器启动就开始了,hibernate销毁结束
hibernate本身对二级缓存没有实现,是借助第三方插件实现的
公有数据的特征
1.一般情况下保持不变
所有的人都能访问
访问的频率比较高
安全性不是特别高的数据
配置
1. hibernate.cfg.xml
2.src 下的ehcache.xml文件
3.class映射文件
案例一
案例二
说明:session.save方法不进二级缓存
案例三
案例四
说明:
执行55行代码的时候,把classes表中的所有的对象进入到了二级缓存中
执行59行代码的时候,重新从数据库中查找记录
所以createQuery(hql).list方法能把一个对象放入到二级缓存中,但是不利用二级缓存获取对象。
案例五
在classpath的根目录下放置一个ehcache.xml文件
从上述的配置可以看出,classes对象在内存中存放的数量最多为5个,多余的对象将存在磁盘上。
查找classes表中所有的对象,在内存中放置5个对象,剩余的对象将被存在磁盘上
案例六
相当于开启了classes类中的set集合的二级缓存
把集合放入到了二级缓存中。
读写策略
Usage
Ready-only
只能把一个对象放入到二级缓存中不能修改
Read-write
能把一个对象放入到二级缓存中,也能修改
查询缓存
概念:就是数据缓存 按照需求加载数据
一级缓存和二级缓存都是对象缓存 表中与多少个字段 就会加载多少个数据
配置
1建立在二级缓存基础上
2开启查询缓存
案例一
说明:
当执行24行代码的时候,发出sql语句
当执行30行代码的时候,没有发出sql语句,因为利用了查询缓存
案例二
说明:
1、 当两次query.list的时候,都会发出sql语句
2、 原因是两次的查询hql语句不一样。
3、 从这里可以看出查询缓存的命中率比较低
案例三
从list的内存快照中可以看出,list里存放的不是持久化对象,而是name属性的值。
一级缓存和二级缓存存放的是持久化对象,如果集合中存放的不是持久化对象,则不能进入二级缓存中,但是能够进入查询缓存中。
数据缓存和对象缓存
1、 一级缓存和二级缓存是对象缓存,只能缓存持久化对象
2、 对象缓存的特别就是要把数据库表中所有的字段全部查询出来
3、 查询缓存是数据缓存,可以查询一个对象的部分属性,而且可以把部分属性放入到查询缓存中,查询缓存也支持对象。命中率低
hibernate二级缓存和查询缓存用得比较少
Hql语句
单表
案例一
from Classes
案例二
说明:List中含有Object[],该数组中有两个元素,第一个元素为Long类型,第二个元素为String类型。
案例三
案例四
案例五
案例六
案例七 动态参数
@Test public void testQuery_Dynamic_Parameter(){ /** * key代表持久化类中属性的名称 * value代表属性的值 */ Map<String, String> map = new HashMap<String, String>(); map.put("name","aa"); this.queryDynamic(map, Classes.class); } private void queryDynamic(Map<String, String> map,Class className){ Session session = sessionFactory.openSession(); StringBuffer buffer = new StringBuffer(); /** * classes持久化类的元数据 */ ClassMetadata classMetadata = sessionFactory.getClassMetadata(className); //得到持久化类的名称 buffer.append("from "+classMetadata.getEntityName()); buffer.append(" where 1=1"); //得到map中所有的key值 Set<String> keys = map.keySet(); //拼接hql语句:查询条件 Iterator<String> iterator = keys.iterator(); for(int i=0;i<keys.size();i++){ String temp = iterator.next(); buffer.append(" and "+temp+"=:"+temp); } Query query = session.createQuery(buffer.toString()); /** * 给所有的查询条件赋值 */ for(Entry<String, String> entry:map.entrySet()){ query.setString(entry.getKey(), entry.getValue()); } List<Classes> classesList = query.list(); System.out.println(classesList.size()); session.close(); }
一对多
案例一
数据结构不合适,一般不用
案例二 左外连接
结构不是很好,数据为object类型数组
案例三
数据为Classes数组
案例四 迫切内连接
数据为classes数组
案例五
说明:如果用select,则不能用fetch,如果用fetch,则不能用select。
多对多
案例一
案例二
一对多和多对多 三表内连接
案例一
hibernate内部的list
hibernate内的map
分页
public void testDispage(){ Session session = sessionFactory.openSession(); Query query = session.createQuery(" from Classes "); query.setFirstResult(0);//当前页第一行的在列表中的位置 query.setMaxResults(2);//当前页有多少行 List<Classes> classesList = query.list(); for(Classes c:classesList){ System.out.println(c.getCid()); } session.close(); }
三种查询方式
原生的查询方式
条件查询
hql语句查询