Hibernate之抓取策略

时间:2017-1-23 19:08

——区分延迟和立即检索

1、立即检索
    当执行某行代码时,会马上发出SQL语句进行查询。
    例如:get()

2、延迟检索
    当执行某行代码时,不会马上发出SQL语句,只有当真正使用对象时,才会向数据库发出SQL语句。
    例如:load()

3、示例代码
    /*

* 区分立即检索和延迟检索

*/

public void fun1(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

// 立即检索

Customer customer = (Customer) session.get(Customer.class, 1);

System.out.println(customer);

/*

* 延迟检索

* 当持久化类设置为final之后,延迟检索就失效了,因为不能生成代理对象

* 在Customer.hbm.xml的<class>标签上配置lazy="false",表示不支持延迟检索

*/

Customer customer2 = (Customer) session.load(Customer.class, 1);

// 初始化代理对象

System.out.println(customer2);

Hibernate.initialize(customer2); // 会立即检索

tx.commit();

session.close();

}

——类级别检索和关联级别检索

1、类级别的检索:
    1)类级别可选的检索策略包括立即检索和延迟检索,默认为延迟检索。
    2)类级别的检索策略可以通过<class>元素的lazy属性进行设置。
    3)如果程序加载一个对象的目的是为了访问它的属性,可以采取立即检索的方式,如果程序加载一个持久化对象的目的仅仅是为了获得它的引用,可以采用延迟检索。
    4)无论<class>元素的lazy属性是true还是false,Session的get()方法以及Query的list()方法在类级别总是使用立即检索的策略。
    5)若<class>元素的lazy属性为true或取默认值,Session的load()方法不会执行查询数据表的select语句,而是仅返回代理对象的实例,该代理对象实例有如下特征:
        *   由Hibernate在运行时采用javassist工具动态生成
        *   Hibernate创建代理对象实例时,仅初始化其OID属性
        *   在应用程序第一次访问代理实例的非OID属性时,Hibernate会初始化代理类实例。

2、关联级别的检索
    1)在映射文件中,用<set>元素来配置一对多关联及多对多关联关系,<set>元素中有lazy和fetch属性:
    2)lazy:主要决定orders集合被初始化的时机,即是否在Customer对象初始化时被加载,还是在程序访问orders集合时被初始化。
    3)fetch:取值为select或subselect时,决定初始化orders的查询语句的形式,若取值为join,则决定orders集合被初始化的时机。
    4)若把fetch设置为“join”,lazy属性将被忽略。

——一方关联多方的情况

在<set>元素中包含fetch和lazy属性:
        *   fetch:控制SQL语句的类型
            >   join:采用迫切左外连接查询
            >   select:默认值
            >   subselect:发送子查询来查询关联对象

*   lazy:控制关联对象的检索是否采用延迟
            >   true:默认值,查询关联对象采用延迟检索
            >   false:查询关联对象不使用延迟检索
            >   extra:特懒

join:一次查完
    select:分多次查完

lazy="true":延迟查询
    lazy="false":不延迟查询

如果fetch="join",那么lazy属性将被忽略。

示例代码:
    1)<set>集合中没有配置fetch和lazy的情况
        默认值:fetch="select" lazy="true"

// 只发送查询客户的SQL语句,没有发送查询订单的SQL

Customer customer = (Customer) session.get(Customer.class, 1);

// 使用客户订单信息的时候,才会发送查询订单的SQL语句

System.out.println(customer.getOrders().size());

SQL:

Hibernate:

select

customer0_.cid as cid0_0_,

customer0_.cname as cname0_0_

from

customer customer0_

where

customer0_.cid=?

Hibernate:

select

orders0_.cid as cid0_1_,

orders0_.oid as oid1_,

orders0_.oid as oid1_0_,

orders0_.addr as addr1_0_,

orders0_.cid as cid1_0_

from

order_table orders0_

where

orders0_.cid=?

2)在<set>标签中配置fetch="join",lazy会被忽略

* 只要fetch设置为join,会采用迫切左外连接进行查询

// 直接发送一条迫切左外连接查询,查询全部数据,包括订单信息

Customer customer = (Customer) session.get(Customer.class, 1);

System.out.println(customer.getOrders().size());

SQL:
            Hibernate:

select

customer0_.cid as cid0_1_,

customer0_.cname as cname0_1_,

orders1_.cid as cid0_3_,

orders1_.oid as oid3_,

orders1_.oid as oid1_0_,

orders1_.addr as addr1_0_,

orders1_.cid as cid1_0_

from

customer customer0_

left outer join

order_table orders1_

on customer0_.cid=orders1_.cid

where

customer0_.cid=?

3)在<set>标签中配置fetch="select" lazy="extra"

* lazy="extra" 极其懒惰

// 只查询Customer的信息,不查询关联对象信息

Customer customer = (Customer) session.get(Customer.class, 1);

// 当查询数量时,只会发送:select count(*) from order_table where oid = ?

System.out.println(customer.getOrders().size());

// 当查询订单时,才会查询全部订单信息:selecg * from order_table

System.out.println(customer.getOrders());

SQL:
            Hibernate:

select

customer0_.cid as cid0_0_,

customer0_.cname as cname0_0_

from

customer customer0_

where

customer0_.cid=?

Hibernate:

select

count(oid)

from

order_table

where

cid =?

Hibernate:

select

orders0_.cid as cid0_1_,

orders0_.oid as oid1_,

orders0_.oid as oid1_0_,

orders0_.addr as addr1_0_,

orders0_.cid as cid1_0_

from

order_table orders0_

where

orders0_.cid=?

4)在<set>标签中配置fetch="subselect" lazy="true"

* 使用subselect的时候需要使用Query接口进行测试,因为需要查询多个客户,才能看到子查询的效果

* 查询一个客户和查询多个客户有什么区别?

*   > 如果只有一个客户会使用:=

*   > 如果有多个客户会使用:in

List<Customer> list = session.createQuery("from Customer").list();

for(Customer c : list){

System.out.println(c.getOrders().size());

}

SQL:
            Hibernate:

select

customer0_.cid as cid0_,

customer0_.cname as cname0_

from

customer customer0_

Hibernate:

select

orders0_.cid as cid0_1_,

orders0_.oid as oid1_,

orders0_.oid as oid1_0_,

orders0_.addr as addr1_0_,

orders0_.cid as cid1_0_

from

order_table orders0_

where

orders0_.cid in (

select

customer0_.cid

from

customer customer0_

)

——多方关联一方的情况

1、多对一和一对一关联的检索策略,和<set>一样,<many-to-one>元素也有一个lazy属性和fetch属性:
    *   若fetch属性设为join,那么lazy属性被忽略。
    *   迫切左外连接检索策略的优点在于比立即检索策略使用的select语句更少。
    *   无代理延迟检索需要增强持久化类的字节码才能实现。

2、Query的list()方法会忽略映射文件配置的迫切左外连接检索策略,而采用延迟检索或立即检索策略,根据Customer类级别的lazy属性进行检索,lazy="true"为延迟检索,lazy="false"为立即检索。

3、如果在关联级别使用了延迟加载或立即加载检索策略,可以设定批量检索的大小,以帮助提高延迟检索或立即检索的运行性能。

4、<many-to-one>
    *   fetch:控制SQL语句发送格式
        >   join:使用迫切左外连接查询,lazy会被忽略
        >   select:发送多条SQL检索对象
    *   lazy:关联对象检索的时候,是否采用延迟
        >   false:不延迟
        >   proxy:使用代理,检索订单时是否马上检索客户,由Customer对象的映射文件中<class>元素的lazy属性来决定
        >   no-proxy:不使用代理

示例代码:
    1)没有在<many-to-one>标签上进行配置

* 发送多条SQL来查询订单中的信息

// 只查询订单的记录,拿到的是关联Customer的引用

Order order = (Order) session.get(Order.class, 1);

// 使用订单的Customer对象时,会发送一条SQL查询订单关联的客户对象的信息

System.out.println(order.getCustomer().getCname());

SQL:
            Hibernate:

select

order0_.oid as oid1_0_,

order0_.addr as addr1_0_,

order0_.cid as cid1_0_

from

order_table order0_

where

order0_.oid=?

Hibernate:

select

customer0_.cid as cid0_0_,

customer0_.cname as cname0_0_

from

customer customer0_

where

customer0_.cid=?

2)在<many-to-one>标签上进行配置

* fetch="join" lazy会被忽略
            * 发送迫切左外连接

// 发送一条迫切左外连接,将全部信息都获取到,并且封装到对象中

Order order = (Order) session.get(Order.class, 1);

System.out.println(order.getCustomer().getCname());

SQL:
            Hibernate:

select

order0_.oid as oid1_1_,

order0_.addr as addr1_1_,

order0_.cid as cid1_1_,

customer1_.cid as cid0_0_,

customer1_.cname as cname0_0_

from

order_table order0_

left outer join

customer customer1_

·  on order0_.cid=customer1_.cid

where

order0_.oid=?

3)在<many-to-one>标签上设置
            * fetch="select" lazy="false"

// 发送多条SQL,不延迟,一次查完

Order order = (Order) session.get(Order.class, 1);

System.out.println(order.getCustomer().getCname());

SQL:
            Hibernate:

select

order0_.oid as oid1_0_,

order0_.addr as addr1_0_,

order0_.cid as cid1_0_

from

order_table order0_

where

order0_.oid=?

Hibernate:

select

customer0_.cid as cid0_0_,

customer0_.cname as cname0_0_

from

customer customer0_

where

customer0_.cid=?

——批量抓取

1、从一方批量抓取多方记录

在Customer.hbm.xml的<set>标签上配置batch-size="2"

* 表示一次查询两个

示例代码:
    List<Customer> list = session.createQuery("from Customer").list();

for(Customer customer : list){

for(Order order : customer.getOrders()){

System.out.println(order.getAddr());

}

}

SQL:

Hibernate:

select

customer0_.cid as cid0_,

customer0_.cname as cname0_

from

customer customer0_

Hibernate:

select

orders0_.cid as cid0_1_,

orders0_.oid as oid1_,

orders0_.oid as oid1_0_,

orders0_.addr as addr1_0_,

orders0_.cid as cid1_0_

from

order_table orders0_

where

orders0_.cid in (

?, ?

)

奎文3

奎文4

奎文1

奎文7

奎文2

奎文0

奎文8

奎文6

奎文9

奎文5

高新2

高新9

高新3

高新8

高新1

高新4

高新0

高新5

高新6

高新7

Hibernate:

select

orders0_.cid as cid0_1_,

orders0_.oid as oid1_,

orders0_.oid as oid1_0_,

orders0_.addr as addr1_0_,

orders0_.cid as cid1_0_

from

order_table orders0_

where

orders0_.cid=?

潍城4

潍城5

潍城6

潍城1

潍城7

潍城0

潍城9

潍城2

潍城3

潍城8

2、从多方批量抓取一方记录
    不能在多方设置batch-size属性,需要在一方的<class>标签上设置batch-size。

——总结

1、立即检索

2、延迟检索
    配置fetch和lazy属性
    *   配置立即检索
        >   lazy="false"
        >   持久化类设置为final
        >   在调用方法的时候,初始化代理对象
3、延迟
    类级别的延迟:
        <class>元素上设置lazy

关联级别的延迟:
        <set> / <many-to-many> / <one-to-one>

4、fetch属性
    *   <set>集合上的fetch:
        >   join:强制使用迫切左外连接
        >   select:默认值,会发送多条SQL语句
        >   subselect:使用子查询
    *   在<many-to-one>标签上使用
        >   select:默认值,发送多条SQL
        >   join:强制使用迫切左外连接

5、lazy属性
    *   <set>
        >   true:默认值,延迟
        >   false:不采用延迟
        >   extra:极其懒惰
    *   <many-to-one>
        >   proxy:根据另一方的<calss>元素配置的lazy来确定是否使用延迟。
        >   false:不采用延迟。
        >   no-proxy

6、batch-size批量抓取
    默认情况下只会检索一条记录,如果想要批量抓取多条记录,可以使用batch-size进行检索。

时间: 2024-08-06 07:49:49

Hibernate之抓取策略的相关文章

Hibernate fetch 抓取策略

上一篇文章(Hibernate的延迟加载 ,懒加载,lazy)说到Hibernate的延迟加载跟fetch的配置还有一定关系,下面就来讨论下fetch的用法. 抓取策略(fetch)是指当我们去查询一个对象里面所关联的其他对象时,按照哪种方法去抓取关联对象. fetch策略一共有四种:select.subselect.join.batch,下面我们一一介绍.我们还是用上面介绍延迟加载的相关表和实体类. Company表: Employee表(employee_company_id为外键) Com

S2JH Hibernate Lazy抓取策略--could not initialize prox

在做 图片上传 相关实体保存时,出现了该错误. 相关Entity     @OneToMany(mappedBy = "objectSid", cascade = CascadeType.ALL, orphanRemoval = true)     @OrderBy("orderIndex desc")     public List<ObjectR2Pic> getShopPagePics() {         return shopPagePics

八 Hibernate延迟加载&amp;抓取策略(优化)

面试:Hibernate效率很低,如何优化? 缓存怎么弄的,语句怎么优化? 聊聊一级缓存,聊聊抓取策略和延迟加载,聊聊批量抓取 延迟加载: 一般不单独使用,和延迟加载一起使用 延迟加载:lazy(懒加载) 执行到该行代码的时候不会发送语句,真正使用这个对象的属性的时候才会发送sql语句进行查询. 类级别延迟加载:指的是是通过load方法查询某个对象的时候是否采用延迟,通过class标签上的lazy来配置. 让类级别延迟加载失效:1 lazy设为false 2 final修饰 3 调用Hibern

hibernate查询&amp;抓取策略优化机制

一 HQL查询 1 一次存1个客户,10个联系人.执行三次,存3个客户,30个联系人,为分页查询做准备 @Test //来3个客户,30个联系人 public void demo1(){ Session session=HibernateUtils.getCurrentSession(); Transaction tx=session.beginTransaction(); Customer customer=new Customer(); customer.setCust_name("小白&q

Hibernate优化---抓取策略

1.延迟加载 类的延迟加载 在类的映射文件中的class标签上配置lazy属性:默认为true,当你配置为false的时候,就算你使用session.load他也会在你调用这个方法之后发送SQL语句,而不是在你使用查询得到的对象的时候才发送SQL语句 关联级别的延迟加载 在类的映射文件中的set和many-to-one上配置lazy属性:默认为true,也就是说,当你查询某个对象是,他不会连带着查询他的关联对象,当你使用这些关联对象的时候才会发送SQL语句查询 2.抓取策略 set上的fetch

Hibernate的抓取策略

立即检索:当执行某行代码的时候,马上发出SQL语句进行查询(get())延迟检索:当执行某行代码的时候,不会马上发出SQL语句进行查询.当真正使用这个对象的时候才会发送SQL语句(load()) 类级别检索和关联级别检索 类级别的检索:<class>标签上配置lazy 关联级别的检索:<set>/<many-to-one>上面的lazy 从一的一方关联多的一方(<set>) fetch:控制sql语句的类型 join :发送迫切左外连接的SQL查询关联对象.

hibernate抓取策略学习

一.hibernate抓取策略概述 Hibernate抓取策略(fetching strategy)是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略.抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或条件查询(Criteria Query)中重载声明. 需要注意的是:hibernate的抓取策略只影响get load 方法,对hql是不影响的. 二.hibernate 抓取策略分类 hibernate有如下

Hibernate 优化技术之抓取策略(Fetching strategies)

一.前言 转载请标明出处:http://blog.csdn.net/wlwlwlwl015/article/details/42705585 使用hibernate一年多了,一直觉得他是一个很好用的持久层框架,在处理含有多个复杂的关联关系的数据表时,hibernate提供的各种关联映射可以让我们用少量的代码快速.便捷的去维护各种外键关系,当然他的核心还是允许我们以"面向对象"的方式去操作数据表,因为我们的Java语言就是面向对象的,所以我们使用ORM的持久层框架应该更容易理解和上手,他

【Hibernate 8】Hibernate的调优方法:抓取策略

在上一篇博客中,介绍了Hibernate的缓存机制.合理的配置缓存,可以极大程度上优化Hibernate的性能.这篇博客,介绍另外一个调优方式:抓取策略. 一.什么是抓取策略 抓取策略(fetching strategy):当应用程序需要在关联关系间进行导航的时候,Hibernate如何获取关联对象的策略.抓取策略可以在O / R映射的元数据中声明,也可以在特定的HQL或条件查询(Criteria Query)中重载声明. 二.Hibernate的抓取策略 在Hibernate中,主要包括四种抓