类级别的检索策略:
Customer c=(Customer)session.load(Customer.class, 1);
session的方法直接检索Customer对象,对Customer对象到底采用立即检索,还是延迟检索方式,通过class元素的lazy属性设定
get():默认立即检索
load():默认延迟检索
public void loadCustomertrueProxy(){
Session session=sessionFacoty.openSession();
Transaction tx=session.beginTransaction();
//此时查询到的c对象是一个代理对象
Customer c=(Customer)session.load(Customer.class, 1);
System.out.println(c.getClass()); //代理对象
c.getClass(); //hibernate不会执行select语句
c.getId(); //hibernate不会执行select语句
c.getAge(); //该行hibernate会执行select语句
tx.commit();
session.close();
}
Hiberante提供了一个工具类,可以在load()延迟加载的情况下手动加载
public void loadCustomertrueProxyInit(){
Session session=sessionFacoty.openSession();
Transaction tx=session.beginTransaction();
//此时查询到的c对象是一个代理对象
Customer c=(Customer)session.load(Customer.class, 1);
System.out.println(c.getClass()); //代理对象
//判断代理对象是否被初始化 对集合对象也适用
if(!Hibernate.isInitialized(c)){
System.out.println(c.getClass()); //代理对象
System.out.println("没有被初始化");
//方法一
c.getAge();//会查询select语句
//初始化代理对象的方法,hibernate执行select查询,方法二
Hibernate.initialize(c);
}
tx.commit();
session.close();
}
get/load在Hibernate part 4中已经详细的解释过了
通过修改配置文件,load()可以实现立即检索
<class name="rock.lee.bean.Customer" table="customer" catalog="test" lazy="false">
此时load()检索方式和get()一样,不会生成代理对象,立即查询Customer对象
无 论 <class> 元素的 lazy 属性是 true 还是 false, Session 的 get() 方法及 Query 的 list() 方法在类级别总是使用立即检索策略;若 <class> 元素的 lazy 属性为 true 或取默认值, Session 的 load() 方法不会执行查询数据表的 SELECT 语句
关联级别检索策略:
在映射文件中, 用 <set> 元素来配置一对多关联及多对多关联关系,<set> 元素有 lazy 和 fetch 属性
lazy: 主要决定 orders 集合被初始化的时机. 即到底是在加载 Customer 对象时就被初始化, 还是在程序访问 orders 集合时被初始化
fetch: 取值为 “select” 或 “subselect” 时, 决定初始化 orders 的查询语句的形式; 若把 fetch 设置为 “join”, lazy 属性将被忽略
建立测试数据:
mysql> select * from orders;
+----+---------------+-------+-------------+
| id | address | money | customer_id |
+----+---------------+-------+-------------+
| 1 | 林允儿...一环 | 11 | 1 |
| 2 | 林允儿...一环 | 11 | 1 |
| 3 | 林允儿...一环 | 11 | 1 |
| 4 | 林允儿...一环 | 11 | 1 |
| 5 | 林允儿...一环 | 11 | 1 |
| 6 | 林允儿...一环 | 11 | 1 |
| 7 | 孙艺珍...一环 | 11 | 2 |
| 8 | 孙艺珍...一环 | 11 | 2 |
| 9 | 孙艺珍...一环 | 11 | 2 |
| 10 | 孙艺珍...一环 | 11 | 2 |
| 11 | 孙艺珍...一环 | 11 | 2 |
| 12 | 孙艺珍...一环 | 11 | 2 |
+----+---------------+-------+-------------+
12 rows in set (0.00 sec)
mysql> select * from customer;
+----+--------+------+
| id | name | city |
+----+--------+------+
| 1 | 林允儿 | SH |
| 2 | 孙艺珍 | BJ |
+----+--------+------+
2 rows in set (0.00 sec)
修改配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="rock.lee.bean.Customer" table="customer" catalog="test" > <id name="id" column="id" type="int"> <generator class="native"></generator> </id> <set name="orders" cascade="save-update,delete,delete-orphan" inverse="true" fetch="join"> <!-- customer表order是中所生成的外键列 --> <key column="customer_id"></key> <one-to-many class="rock.lee.bean.Order" /> </set> <property name="name" column="name" type="java.lang.String"></property> <property name="city" column="city" type="java.lang.String"></property> </class> </hibernate-mapping>
查询ID为1的Custoemr数据
@Test
public void test02() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer c1 = (Customer) session.get(Customer.class,1);
transaction.commit();
session.close();
}
由于使用的是关联查询,所以lazy属性被忽略,立刻查询
Hibernate:
select
customer0_.id as id0_1_,
customer0_.name as name0_1_,
customer0_.city as city0_1_,
orders1_.customer_id as customer4_0_3_,
orders1_.id as id3_,
orders1_.id as id1_0_,
orders1_.address as address1_0_,
orders1_.money as money1_0_,
orders1_.customer_id as customer4_1_0_
from
test.customer customer0_
left outer join
test.orders orders1_
on customer0_.id=orders1_.customer_id
where
customer0_.id=?
案例二:fetch="select" 多条简单SQL
lazy="false" 立即检索
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="rock.lee.bean.Customer" table="customer" catalog="test" > <id name="id" column="id" type="int"> <generator class="native"></generator> </id> <set name="orders" cascade="save-update,delete,delete-orphan" inverse="true" fetch="select" lazy="false"> <!-- customer表order是中所生成的外键列 --> <key column="customer_id"></key> <one-to-many class="rock.lee.bean.Order" /> </set> <property name="name" column="name" type="java.lang.String"></property> <property name="city" column="city" type="java.lang.String"></property> </class> </hibernate-mapping>先查customer,在查orders,使用的都是简单查询语句
Hibernate:
select
customer0_.id as id0_0_,
customer0_.name as name0_0_,
customer0_.city as city0_0_
from
test.customer customer0_
where
customer0_.id=?
Hibernate:
select
orders0_.customer_id as customer4_0_1_,
orders0_.id as id1_,
orders0_.id as id1_0_,
orders0_.address as address1_0_,
orders0_.money as money1_0_,
orders0_.customer_id as customer4_1_0_
from
test.orders orders0_
where
orders0_.customer_id=?
lazy="true" 延迟检索
<set name="orders" cascade="save-update,delete,delete-orphan" inverse="true" fetch="select" lazy="true">
也是两条简单SQL语句,但因为是延迟检索,所以获取order数据是才会查询orders表
lazy="extra" 极其懒惰 (比延迟更加延迟) 增强延迟检索
<set name="orders" cascade="save-update,delete,delete-orphan" inverse="true" fetch="select" lazy="extra">
@Test
public void test02() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer c1 = (Customer) session.get(Customer.class,1);
System.out.println(c1.getOrders().size());
System.out.println(c1.getOrders().iterator().next().getAddress());
transaction.commit();
session.close();
}
只要不查看order中的数据,就不会发出查询语句
--Hibernate: Customer c1 = (Customer) session.get(Customer.class,1);
select
customer0_.id as id0_0_,
customer0_.name as name0_0_,
customer0_.city as city0_0_
from
test.customer customer0_
where
customer0_.id=?
--Hibernate: System.out.println(c1.getOrders().size());
select
count(id)
from
test.orders
where
customer_id =?
--Hibernate: System.out.println(c1.getOrders().iterator().next().getAddress());
select
orders0_.customer_id as customer4_0_1_,
orders0_.id as id1_,
orders0_.id as id1_0_,
orders0_.address as address1_0_,
orders0_.money as money1_0_,
orders0_.customer_id as customer4_1_0_
from
test.orders orders0_
where
orders0_.customer_id=?
lazy="false" 立即检索
lazy="true" 延迟检索
lazy="extra" 极其懒惰 (增强延迟检索)
SQL的查询型式是子查询
- 当设置 <set> lazy="true" 第一次调用 集合 size()、 iterator() 、isEmpty() 、contains() 都会调用Hibernate.initialize() 对延迟集合初始化
- 当设置 <set> lazy="extra" 调用集合 iterator()导致集合初始化, 调用 size() 、isEmpty() 、contains() 不会对集合初始化
- 使用get/load 查询customer时,配置fetch="join" 采用迫切左外连接查询,order会被查询, 采用立即检索 lazy被忽略,如果使用Query的list方法查询,根据HQL生成SQL语句,fetch="join" 会被忽略 , lazy 重新生效
批量检索: