Hibernate_检索策略

本文深入探讨Hibernate中的懒加载机制,包括其对Customer和Orders类的影响、不同配置下的行为差异、集合属性的代理类特性以及批量加载策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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"。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值