Customer.java
private int id;
private String name;
private Integer age;
private String address;
private Set orderses = new HashSet(0);
Orders.java
private Integer id;
private Customer customer;
private String product;
private Integer amount;
Customer和Orders是一对多双向关联。
System.out.println("customer...load");
Customer customer=(Customer) session.load(Customer.class,new Integer(1));
System.out.println("customer...getName()");
System.out.println(customer.getName());
当Customer映射文件中设置class级别的lazy="true"时
控制台输出:
customer...load
customer...getName()
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_,
customer0_.age as age3_0_0_,
customer0_.address as address4_0_0_
from
lazystudy.customer customer0_
where
customer0_.id=?
lazyzhong
当lazy="false"时
customer...load
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_,
customer0_.age as age3_0_0_,
customer0_.address as address4_0_0_
from
lazystudy.customer customer0_
where
customer0_.id=?
customer...getName()
lazyzhong
由前面的输出信息可以看出,当lazy="false"时,执行session.load()时,hibernate会立即执行select查询语句。当lazy="true"时,执行session.load()时,不会执行
select语句,返回的是OID为1的Customer代理类,当执行customer.getName()时,hibernate才会执行select语句,初始化Customer代理类。
代理类的特征:
1、hibernate在运行时动态生成,扩展了Customer类,继承了Customer的所有属性和方法。(hibernate采用CGLIB工具生成)
2、hibernate创建代理类实例时,仅初始化了OID,其他属性都为null,所有占得内存很少。
3、当程序第一次访问代理类实例时(getXXX或setXXX),hibernate才会初始化代理类(通过select语句),但是访问getId时不会初始化,因为在创建代理类实例的时候
就已经生成了OID。
不管<class>元素中的lazy为true还是false,当调用Session的get方法或Query的list()方法时,总是使用立即检索策略。当执行list()方法时,如果与Customer关联的Orders
对象采用的是延迟加载,则hibernate只会立即到数据库中加载Customer对象,而不会加载关联的Orders对象。
一对多和多对多关联的检索策略
<set>元素有lazy和fetch属性:
lazy:决定集合被初始化的时机,决定是采取立即加载还是延迟加载。
fetch:取值为"select"或"subselect"时,觉得初始化时查询语句的形式;当取值为"join"时决定初始化时机。
与持久化类的代理类不同,不管有没有采取延迟策略,hibernate的各种检索方法在为Set集合属性赋值时,Set属性总是引用集合代理类。
当lazy="false"时,会立即加载Customer和Orders对象。
当lazy="true",仅加载Customer对象,Customer的orders属性引用一个没有被初始化的集合代理类实例,orders初始化的情况:
(1)当第一次使用它的contains、size、iterator等方法时。
(2)通过org.hibernate.Hibernate的initialize方法初始化。
当layz="extra"时,和lazy="true"差不多,但是它会进一步延迟orders属性初始化的时机,当第一次使用它的contains、size、iterator等方法时,并不会初始化,
而是会用特定的sql语句来进行查询得到结果。
eg:
customer.getOrderses().size()
控制台输出:
select
count(id)
from
lazystudy.orders
where
customer_id =?
批量延迟检索和批量立即检索:
当lazy="true"
MyTest.java
Customer customer1=(Customer) session.get(Customer.class,new Integer(1));
Customer customer2=(Customer) session.get(Customer.class,new Integer(2));
customer1.getOrderses().iterator();
customer2.getOrderses().iterator();
控制台输出
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_,
customer0_.age as age3_0_0_,
customer0_.address as address4_0_0_
from
lazystudy.customer customer0_
where
customer0_.id=?
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_,
customer0_.age as age3_0_0_,
customer0_.address as address4_0_0_
from
lazystudy.customer customer0_
where
customer0_.id=?
Hibernate:
select
orderses0_.customer_id as customer2_0_1_,
orderses0_.id as id1_1_1_,
orderses0_.id as id1_1_0_,
orderses0_.customer_id as customer2_1_0_,
orderses0_.product as product3_1_0_,
orderses0_.amount as amount4_1_0_
from
lazystudy.orders orderses0_
where
orderses0_.customer_id=?
Hibernate:
select
orderses0_.customer_id as customer2_0_1_,
orderses0_.id as id1_1_1_,
orderses0_.id as id1_1_0_,
orderses0_.customer_id as customer2_1_0_,
orderses0_.product as product3_1_0_,
orderses0_.amount as amount4_1_0_
from
lazystudy.orders orderses0_
当再加上batch-size="2"时,控制台输出
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_,
customer0_.age as age3_0_0_,
customer0_.address as address4_0_0_
from
lazystudy.customer customer0_
where
customer0_.id=?
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_,
customer0_.age as age3_0_0_,
customer0_.address as address4_0_0_
from
lazystudy.customer customer0_
where
customer0_.id=?
Hibernate:
select
orderses0_.customer_id as customer2_0_1_,
orderses0_.id as id1_1_1_,
orderses0_.id as id1_1_0_,
orderses0_.customer_id as customer2_1_0_,
orderses0_.product as product3_1_0_,
orderses0_.amount as amount4_1_0_
from
lazystudy.orders orderses0_
where
orderses0_.customer_id in (
?, ?
)
这是因为当访问customer1.getOrders().iteratot()方法时,Session的缓存中有2个orders集合代理类实例没有被初始化,由于batch-size=2,所以会一次性初始化2个orders集合代理类实例。
当lazy="flase",batch-size="2"时,session.createQuery("from Customer").list();
控制台输出
Hibernate:
select
customer0_.id as id1_0_,
customer0_.name as name2_0_,
customer0_.age as age3_0_,
customer0_.address as address4_0_
from
lazystudy.customer customer0_
Hibernate:
select
orderses0_.customer_id as customer2_0_1_,
orderses0_.id as id1_1_1_,
orderses0_.id as id1_1_0_,
orderses0_.customer_id as customer2_1_0_,
orderses0_.product as product3_1_0_,
orderses0_.amount as amount4_1_0_
from
lazystudy.orders orderses0_
where
orderses0_.customer_id in (
?, ?
)
当fetch="subselect"、batch-size="2"时,session.createQuery("from Customer").list();
控制台输出
Hibernate:
select
customer0_.id as id1_0_,
customer0_.name as name2_0_,
customer0_.age as age3_0_,
customer0_.address as address4_0_
from
lazystudy.customer customer0_
Hibernate:
select
orderses0_.customer_id as customer2_0_1_,
orderses0_.id as id1_1_1_,
orderses0_.id as id1_1_0_,
orderses0_.customer_id as customer2_1_0_,
orderses0_.product as product3_1_0_,
orderses0_.amount as amount4_1_0_
from
lazystudy.orders orderses0_
where
orderses0_.customer_id in (
select
customer0_.id
from
lazystudy.customer customer0_
)
当fetch="subselect"时,不用设置batch-size,即使设置了也会被忽略,因为它能通过带子查询的查询语句来批量初始化n个代理类实例;而当fetch="select"时,可以设置batch-size。
当fetch="join"时,
Hibernate:
select
customer0_.id as id1_0_1_,
customer0_.name as name2_0_1_,
customer0_.age as age3_0_1_,
customer0_.address as address4_0_1_,
orderses1_.customer_id as customer2_0_3_,
orderses1_.id as id1_1_3_,
orderses1_.id as id1_1_0_,
orderses1_.customer_id as customer2_1_0_,
orderses1_.product as product3_1_0_,
orderses1_.amount as amount4_1_0_
from
lazystudy.customer customer0_
left outer join
lazystudy.orders orderses1_
on customer0_.id=orderses1_.customer_id
where
customer0_.id=?
注意:Query的list()方法会忽略fetch="join"。