fetch检索策略

fetch检索策略用来说明如何把关联对象加载上来!例如使用单独的select语句来加载关联对象;或者使用左外连接加载当前对象和关联对象。

 

  • 单边检索策略   

 

    在单边中设置fetch=join时,由于在加载当前对象时会同时加载关联对象,那么就不可能等到使用关联对象时才去加载关联对象。此时Hibernate使用左外连接加载当前对象和关联对象,这会使关联对象的lazy=true失效。   

    这里我们使用Order和Customer来说明。其中一个Customer中可以有有多个Order,建立相应的实体类和.hbm.xml文件,在Order.hbm.xml中我们把<many-to-one>元素的fetch属性设置为join;

 

<many-to-one name="customer" column="customerid" fetch="join"/>
 

 

 下面是加载Order对象的测试代码:

 

			Order o = (Order)session.load(Order.class, 1);
			o.getOrderNumber();
			Customer c = o.getCustomer();
			c.getName();

 

 
 下面是代码执行结果:

 

 

Hibernate: select order0_.id as id1_1_, order0_.orderNumber as orderNum2_1_1_, order0_.customerid as customerid1_1_, customer1_.id as id0_0_, customer1_.name as name0_0_ from orders order0_ left outer join customer customer1_ on order0_.customerid=customer1_.id where order0_.id=?

 

 

结果分析:

1.在执行sesseion.load()方法时不会去加载Order对象,更不会加载关联对象Customer。原因是<class>元素的lazy默认为true,只有在使用Order对象时才会加载Order对象

2.在执行o.getOrderNumber()时会使用左外连接加载Order对象,以及Order所关联的Customer对象。原因是<many-to-one>fetch的值为join。

若此时fetch=select,则此时会输出

 

 

Hibernate: select order0_.id as id1_0_, order0_.orderNumber as orderNum2_1_0_, order0_.customerid as customerid1_0_ from orders order0_ where order0_.id=?

 

Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_ from customer customer0_ where customer0_.id=?
  3.在执行o.getOrderNumber()时,Hibernate会加载Order对象,但不会加载相关联对象Customer,原因是<many-to-one>元素的fetch属性值为select。
4.在执行o.getCustomer()方法时也不会加载Customer对象,因为这时还没有使用Customer对象。如果Customer对应的<class>元素的lazy=false时,效果就不一样了,在执行o.getOrderNumber()方法时就会使用左外连接加载Order对象,以及关联对象Customer。也就是说,关联对象的类级别lazy=false时,那么fetch的默认值为join。
5.在执行c.getName()时执行一条select语句来加载Customer对象

 

 

  • 集合一端的fetch

 

    在集合一端中使用fetch属性,它的可选值为:joinselectsubselect三种。默认值为select

 

 

    <set>fetch=selectfetch=join时,基本与<many-to-one>是相同的,但也有一点不同。在单边fetch中,如果关联对象的类级别lazy=false时,那么fetch的默认值为join,但在集合fetch中,fetch的默认值总是select

fetch=subselect时,来测试上会的例子,我们会发现这与fetch=select没有任何区别。这是因为subselect只有在使用HQL时才会有效果

 

String hql = "from Customer c where c.id in (1,2)";
			List<Customer> cList = session.createQuery(hql).list();
			for(Customer c : cList) {
				c.getName();
				Set<Order> orders = c.getOrders();
				orders.iterator();
			}

 结果为:

 

 

Hibernate: select customer0_.id as id0_, customer0_.name as name0_ from customer customer0_ where customer0_.id in (1 , 2)

Hibernate: select orders0_.customerid as customerid1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.orderNumber as orderNum2_1_0_, orders0_.customerid as customerid1_0_ from orders orders0_ where orders0_.customerid=?

Hibernate: select orders0_.customerid as customerid1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.orderNumber as orderNum2_1_0_, orders0_.customerid as customerid1_0_ from orders orders0_ where orders0_.customerid=?
 

结果分析:

1.在执行session.createQuery(hql).list()时,会执行一条SQL语句来加载两个Customer对象,但不会加载关联对象;

 

2. 在每次执行orders.iteraotr()时会执行一条SQL语句来加载当前Customer对象的关联对象。因为一共有两个Customer对象,所以会执行两条加载关联对象的SQL语句。

 

<set>元素的fetch设置为subselect,再次执行上面的代码,结果如下:

 


Hibernate: select customer0_.id as id0_, customer0_.name as name0_ from customer customer0_ where customer0_.id in (1 , 2)

Hibernate: select orders0_.customerid as customerid1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.orderNumber as orderNum2_1_0_, orders0_.customerid as customerid1_0_ from orders orders0_ where orders0_.customerid in (select customer0_.id from customer customer0_ where customer0_.id in (1 , 2))

 1.在执行session.createQuery(hql).list()时,会执行一条SQL语句来加载两个Customer对象,但不会加载关联对象。这与上面是一样的,没有什么区别

2.在第一次执行orders.iteraotr()时会执行一条子查询SQL语句,它会一次性的加载当前List中所有Customer对象的关联对象。所以在下一次再执行orders.iteraotr()时就不会再执行SQL语句了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值