在hibernate应用中,有时要访问指定的持久化对象,在加载该对象时就没有必需加载其它关联对象,以免浪费内存资源,有时还需要访问其关联的对象。若想在session关闭后依然能正常访问其关联对象,在加载该对象时则需要连同关联对象一并加载。
为了满足不同的需求。hibernate提供了3种检索策略:立即加载,延迟加载,和迫切左外链接加载。
立即加载: lazy=false
表示立即加载和初始化查询方法指定的对象,即使session关闭了,依然可以正常访问,hibernate默认是true,表示延迟加载, 如果要修改为立即加载,我们必须把lazy修改为false。
在orm映射文件中的<class>标签中设置lazy属性表示对该持久化类启用何种加载策略,在类的级别上,一般采用立即加载的策略,因为加载了持久化对象后会立即访问它。
<class name="Customer" table="customer" lazy="false">
当执行如下代码时
load默认支持延迟加载,如果lazy配置了false表示load延迟加载失效
Customer cutomer = (Customer)session.load(Customer.class,1);
向服务器发送的sql为
select* from customer where id=1
select * from orders where customer_id=1
发送2条sql语句
当加载Customer对象时,也会连同其关联对象一起加载,如果不需要访问其关联对象,会浪费大量的内存资源。
Iiterator
Iterator iterator = session.CreateQuery("from Customer as a ").list().Iterator();//加载所有顾客
Hibernate先数据库发送的sql
select * from customer
select * from orders where customer_id=1
select * from orders where customer_id=2
select * from orders where customer_id=3
会发4条sql效率非常低,占内存。
这个时候我们可以用批量来取,在set标签中设置 batch-size="3"
这时的sql语句为
select * from customer
select * from orders where customer_id in(1,2,3)
注意,不管在<class>标签中lazy如果设置何值,也就是说不管类别启用何种检索策略,当使用session实例的get()方法装在持久化对象时均使用立即检索。
也就是get方法不支持延迟加载。
延迟加载 lazy=true
hibernate默认是表示延迟加载,所以lazy默认为true
在orm映射文件中<set>标签中设置lazy属性则表示对该持久化类的关联对象启用何种策略,在关联级别上,一般启用延迟加载策略,因为在加载了持久化对象后大多不会立即访问其关联对象,况且当关联对象数据量大时,将其装入内存开销也很大。
<set name="orders" table="selecteditems" lazy="true"
inverse="true" cascade="save-update">
<key column="itemid"></key>
<many-to-many class="com.xiu.hibernate.cascade.Orders"
column="orderid">
</many-to-many>
</set>
立即加载和延迟加载的比较(hibernate默认是延迟加载)
1. 立即加载
配置文件
<set name="orders" cascade="all" inverse="true" lazy="false"> lazy=false表示立即加载,默认为true
测试代码
public static void main(String[] args) {
SessionFactory sessionFactory = HibernateSessionFactory
.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer c = (Customer) session.load(Customer.class, 1);
tx.commit();
System.out.println(c.getBank());
}
运行结果:
Hibernate:
select
customer0_.id as id0_0_,
customer0_.cname as cname0_0_,
customer0_.phone as phone0_0_,
customer0_.bank as bank0_0_
from
customer customer0_
where
customer0_.id=?
Hibernate:
select
orders0_.customer_id as customer4_1_,
orders0_.id as id1_,
orders0_.id as id4_0_,
orders0_.orderno as orderno4_0_,
orders0_.money as money4_0_,
orders0_.customer_id as customer4_4_0_
from
orders orders0_
where
orders0_.customer_id=?
招商银行
该结果表示已经查询了2张表。
2。延迟加载
只需要把lazy修改为true
测试代码一样,只是sql的过程不一样,sql只会去查询一个表
Hibernate:
select
customer0_.id as id0_0_,
customer0_.cname as cname0_0_,
customer0_.phone as phone0_0_,
customer0_.bank as bank0_0_
from
customer customer0_
where
customer0_.id=?
招商银行
左外链接加载
select * from customer c LEFT OUTER JOIN orders o on c.ID=o.CUSTOMER_ID
以上是左外链接的sql语句
左外链接加载就是充分利用sql的外链接查询功能,减少select语句的数目。
在Hibernate 中若要启用左外加载策略,只需要将所属标签的outer-join的属性设置为true即可。
1. 默认设置out-join=true
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xiu.hibernate.cascade">
<class name="Customer" table="customer" lazy="false"><!-- 在类的级别上设置为立即加载 -->
<id name="id" column="id" type="int">
<generator class="increment"></generator>
</id>
<property name="cname" type="string" column="cname"></property>
<property name="phone" type="string" column="phone"></property>
<property name="bank" type="string" column="bank"></property>
<set name="orders" cascade="all" inverse="false" outer-join="true"> 默认为true
inverse 若为false表示主控制方负责关联关系的维护,若为true表示
有被控制方来维护关系,默认是false
-->
<key column="customer_id"></key>
<one-to-many class="com.xiu.hibernate.cascade.Orders" />
</set>
</class>
</hibernate-mapping>
测试代码同上
运行结果:
Hibernate:
select
customer0_.id as id0_1_,
customer0_.cname as cname0_1_,
customer0_.phone as phone0_1_,
customer0_.bank as bank0_1_,
orders1_.customer_id as customer4_3_,
orders1_.id as id3_,
orders1_.id as id4_0_,
orders1_.orderno as orderno4_0_,
orders1_.money as money4_0_,
orders1_.customer_id as customer4_4_0_
from
customer customer0_
left outer join
orders orders1_
on customer0_.id=orders1_.customer_id
where
customer0_.id=?
招商银行
sql语句用了左外链接
注意:当使用session.createQuery("from Cusotmer as a").list()查询所有的对象时,左链接检索策略被忽略而失效,这时有lazy属性来决定。
2. 在many-to-one上设置左外链接
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xiu.hibernate.cascade">
<class name="Customer" table="customer" lazy="false"><!-- 在类的级别上设置为立即加载 -->
<id name="id" column="id" type="int">
<generator class="increment"></generator>
</id>
<property name="cname" type="string" column="cname"></property>
<property name="phone" type="string" column="phone"></property>
<property name="bank" type="string" column="bank"></property>
<set name="orders" cascade="all" inverse="false" outer-join="true">
<!-- cascade表示级联,他有以下取值
1. all: 表示所有操作均在关联层级上进行连锁操作
2. save-upate 表示只有save与update操作进行连锁操作
3. delete 表示只有delete操作进行连锁操作
4. all-delete-orphan
inverse 若为false表示主控制方负责关联关系的维护,若为true表示
有被控制方来维护关系,默认是false
-->
<key column="customer_id"></key>
<one-to-many class="com.xiu.hibernate.cascade.Orders" />
</set>
</class>
</hibernate-mapping>
测试代码:查询一个对象
SessionFactory sessionFactory = HibernateSessionFactory
.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//Customer c = (Customer) session.load(Customer.class, 1);
Orders c = (Orders) session.load(Orders.class, 1);
tx.commit();
System.out.println(c.getOrderno());
运行结果:
Hibernate:
select
orders0_.id as id4_1_,
orders0_.orderno as orderno4_1_,
orders0_.money as money4_1_,
orders0_.customer_id as customer4_4_1_,
customer1_.id as id0_0_,
customer1_.cname as cname0_0_,
customer1_.phone as phone0_0_,
customer1_.bank as bank0_0_
from
orders orders0_
inner join
customer customer1_
on orders0_.customer_id=customer1_.id
where
orders0_.id=?
订单1
测试代码:查询所有对象
hibernate配置文件还是一样,
测试代码
SessionFactory sessionFactory = HibernateSessionFactory
.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//Customer c = (Customer) session.load(Customer.class, 1);
List<Orders> list = (List<Orders>) session.createQuery(
"from Orders as o").list();
for (Orders orders : list) {
System.out.println(orders.getOrderno());
System.out.println(orders.getCustomer().getCname());
}
tx.commit();
运行结果:
Hibernate:
select
orders0_.id as id4_,
orders0_.orderno as orderno4_,
orders0_.money as money4_,
orders0_.customer_id as customer4_4_
from
orders orders0_
Hibernate:
select
customer0_.id as id0_1_,
customer0_.cname as cname0_1_,
customer0_.phone as phone0_1_,
customer0_.bank as bank0_1_,
orders1_.customer_id as customer4_3_,
orders1_.id as id3_,
orders1_.id as id4_0_,
orders1_.orderno as orderno4_0_,
orders1_.money as money4_0_,
orders1_.customer_id as customer4_4_0_
from
customer customer0_
left outer join
orders orders1_
on customer0_.id=orders1_.customer_id
where
customer0_.id=?
Hibernate:
select
customer0_.id as id0_1_,
customer0_.cname as cname0_1_,
customer0_.phone as phone0_1_,
customer0_.bank as bank0_1_,
orders1_.customer_id as customer4_3_,
orders1_.id as id3_,
orders1_.id as id4_0_,
orders1_.orderno as orderno4_0_,
orders1_.money as money4_0_,
orders1_.customer_id as customer4_4_0_
from
customer customer0_
left outer join
orders orders1_
on customer0_.id=orders1_.customer_id
where
customer0_.id=?
订单1
小朱
订单2
小朱
定单3
小胡