Hibernate的性能优化——延迟加载(懒加载)
通过asm和cglib两个包实现
1、 session.load()时,系统并没有直接去访问数据库,而是通过new来创建代理对象(代理对象不会为空,不能判定)。
代理对象限制:和代理关联的session关闭之前才能使用
User.getname()或user.getBirthday()和初始化的方式Hibernate.initialize(user),hibernate才会访问数据库,select语句才会输出
User.getClass()和user.getId()不会访问数据库
public static User getUser(int id){
Session session=null;
try{
session=HibernateUtil.getSession();
Class clazz=User.class;
//Useruser=(User) session.get(clazz, id);
User user=(User) session.load(clazz,id);
System.out.println(user.getClass());
//user.getBirthday();
Hibernate.initialize(user);
//---持久态
return user;
}finally{
if(session!=null)
session.close();
}
2、 对象和对象之间存在关联
(1) 一对一关联关系
必须满足三个条件时才能实现懒加载
1)Lazy!=false 2)constrained=”true” 3)fetch=select
当我们查询的是主对象时,将person和idcard做了外连接,查询出person和idcard。没有懒加载。(因为主表不能有constrained=true,所以主表没有懒加载)
static Person query(int id){
Session s=null;
Transaction tx=null;
try{
s=HibernateUtil.getSession();
tx=s.beginTransaction();
//查询
IdCard idCard=null;
Person p=(Person) s.get(Person.class,id);//查主对象没有懒加载
tx.commit();
return p;
}finally{
if(s!=null)
s.close();
}
}
当查询从对象时,对于idcard所关联的person对象是懒加载的。
static IdCard query(int id){
Session s=null;
Transaction tx=null;
try{
s=HibernateUtil.getSession();
tx=s.beginTransaction();
//查询
IdCard idCard=(IdCard) s.get(IdCard.class,id);
Hibernate.initialize(idCard.getPerson());
tx.commit();
return idCard;
}finally{
if(s!=null)
s.close();
}
}
(2) 一对多
1) lazy!=false 2)fetch=select
(3) 多对一
1) lazy!=false 2)fetch=select
(4) 多对多
1) lazy!=false 2)fetch=select
Lazy:指相关联的属性什么时候抓取
Fetch:通过什么方式来进行抓取 select二次select语句查询 Join连接查询,lazy属性就不起作用
抓取策略
抓取策略来直接影响session的get()或load()方法的执行效率。主要有以下两种情况
1、 单端关联(<many-to-one>、<one-to-one>)上的抓取策略
可以给单端关联的映射元素添加fetch属性。Fetch属性可能有两个值
Select:作为默认值,它的策略是当需要使用到关联对象的数据时,另外单独发送一条select语句抓取当前对象的关联对象的数据。即延迟加载。
Join:它的策略是在同一条select语句使用内连接来获得对象的数据和它的关联对象的数据,此时关联对象的延迟加载失败。
2、 集合属性上的抓取策略
在集合属性的映射元素上可以添加fetch属性,它有三个可选值。
Select:作为默认值,它的策略是当需要使用所关联集合的数据时,另外单独发送一条select语句抓取当前对象的关联集合,即延迟加载。
Join:在同一条select语句使用内连接来获得对象的关联集合,此时关联集合上的lazy会失效。
Subselect:另外发送一条查询语句(或子查询语句)抓取在前面查询到的所有实体对象的关联集合。这个策略对HQL的查询也起作用。
关闭延迟加载
延迟加载确实会给程序的查询效率带来好处,但有时明确知道数据需要立即加载的,如果Hibernate先默认使用延迟加载,而后又必须去数据库加载,反而会降低效率。所以需要根据应用程序的实际情况来灵活控制是否使用延迟加载。在Hibernate中只需要修改相应的配置来启用或关闭延迟加载的功能。
1、 在加载单个实体,如果不需要延迟加载,就可以使用session的get()方法。
2、 当session加载某个实体时,不需要对这个实体中的集合属性值延迟加载,而是要立即加载。这时可以在映射文件针对这个集合的配置元素(<set>、<bag>、<list>…)添加属性lazy=false。
3、 当session加载某个实体时,不需要对这个实体所单端关联的另一个实体对象延迟加载,就可以在映射文件中针对这个单端关联的配置元素(<ont-to-one>、<many-to-one>)添加属性lazy=false。