5.1 Hibernate的检索策略有:立即检索、延迟检索、迫切左外连接检索。
5.1.1 首先介绍一对多和多对多关系的检索策略
有两个表orders、customers orders与customers是多对一关系。Orders外键customer_id参照customers表的主键id,如下所示:
orders表 Customers表
Id order_id customer_id id name
1 order1 1 1 tom
2 order2 1 2 peter
3 order3 2 3 kallen
在映射文件中,用<set>元素来配置一对多及多对多关联关系。
如:
<set name=“orders” inverse=“true” >
<key column=“coustomer_id”>
<one-to-many class=“mypack.order”>
</set>
以下代码通过session的get()方法加载OID为1的Customer 对象.
tx = session.beginTransaction();
Customer customer = (Customer) session.get(Customer.class,new Long(1));
Set orders = customer.getOrders();
Iterator it = orders.iterator();
5.1.1 .1 立即检索策略
执行session的get方法时,如果采用立即检索策略,Hibernate会执行以下select 语句:
Select * from customers where id=1;
Select * from orders where customer_id=1;
通过以下select 语句,Hibernate加载了一个Customer对象和两个order对象.Customer对象的orders属性引用的是一个Hibernate提供的Set集合类实例,这个实例引用了两个order对象.现在,如果不需要orders表中的数据那么以上sql语句中,第二个语句就白白浪费了时间和内存。
5.1.1 .2 延迟检索策略
对于set元素应该优生考虑延迟检索策略.
<set name=“orders” inverse=“true” lazy=“true”>(lazy的默认值是:false)
此时运行session的get()方法时,立即检索Customer对象,不对order对象进行检索。仅执行以下select 语句:
select * form customer where id=1
这样,在不需要orders表数据的情况下可以避免无谓的操作。此时,没有创建order实例,当需要时,Hibernate会初始化order对象。
5.1.1 .3 批量延迟检索
<set>元素的batch-size 属性,用于为延迟检索或立即检索策略设定批量检索的数量。
当lazy=true时,为批量延迟检索。
以下Session的find方法,用于检索所有的Customer对象:
tx = session.beginTransaction();
List customerLists = session.find(“from customer as c”);
Iterator it = customerLists.iterator();
Customer customer1 = (Customer)customerIterator.next();
Customer customer2 = (Customer)customerIterator.next();
Customer customer3 = (Customer)customerIterator.next();
Iterator orderIterator1 = customer1.getOrder().iterator();
Iterator orderIterator2 = customer2.getOrder().iterator();
Iterator orderIterator3 = customer3.getOrder().iterator();
当session的find方法检索Customer对象时,仅立即执行检索Customer对象的select 语句. Select * from customers;
在customers表中共有四条记录,因此,Hibernate将创建四个Customer对象,它们的orders属性各自引用一个代理类实例。
当执行 Iterator orderIterator1 = customer1.getOrder().iterator(); 方法时,会初始化OID 为1的Customer对象的orders对象,Hibernate执行的select语句为:
Select * from orders where customer_id=1。
当执行 Iterator orderIterator2 = customer2.getOrder().iterator(); 方法时,会初始化OID 为2的Customer对象的orders对象,Hibernate执行的select语句为:
Select * from orders where customer_id=2。依次类推。由此可见,初始化三个orders集合类实例,Hibernate必须执行三条查询语句。为了减少select语句的数目,可以采用批量延迟检索,即设置<set>元素的batch-size属性:
<set name=“orders” inverse=“true” lazy=“true” batch-size=3>
这样,当访问Iterator orderIterator1 = customer1.getOrder().iterator()方法时, Session的缓存中共有三个orders集合类实例未被初始化,现在batch-size=3,因此会批量初始化三个orders集合类实例,Hibernate会执行的select的语句为:
Select * from orders where customer=1 or customer=2 or customer=3。当访问Iterator orderIterator2 = customer2.getOrder().iterator()时,不需要初始化它的orders集合类实例。
5.1.1 .4 批量立即检索
对于find 方法,List customerLists = session.find(“from customer as c”);
当 orders集合默认为立即检索策略时,<set name=“orders” inverse=“true”>
find方法会立即执行以下语句:
select * from customers;
select * from orders where customer_id=1;
select * from orders where customer_id=2;
select * from orders where customer_id=3;
为了减少 select 语句数量,可以设置 set元素的batch-size属性。
如: <set name=“orders” inverse=“true” batch-size=2>
此时,find方法会立即执行以下sql语句:
select * from customers;
select * from orders where customer_id=1 or customer_id=2;
select * from orders where customer_id=3;
如batch-size=3,此时find()方法会立即执行以下sql语句:
select * from customers;
select * from orders where customer_id=1 or customer_id=2 or customer_id=3;
5.1.1 .5 迫切左外连接检索
如果把outer-join设备true。
即:<set name=“orders” inverse=“true” outer-join=“true”>
当执行customer = (Customer)session.get(Customer.class,new Long(1));
时,会执行以下sql语句:
Select * from customers left outer join orders on customer.id=orders.customer_id where customer.id=1;
值得注意的是:session的find方法,会忽略映射文件中配置的迫切左外连接,即使outer-join=true,当用List customer = session.find(“from customer as c”);时,
Hibernate对Customer对象的orders 集合仍然采用立即检索策略,Hibernate会执行的select 语句为:
Select * from customer;
Select * from orders where customer_id=1;
Select * from orders where customer_id=2;
Select * from orders where customer_id=3;