Hibernate 检索策略

1.       类级别检索策略

      1.1          立即检索

      1.2          延迟检索

2.       一对多和多对多关联的检索策略

      2.1 批量延迟和批量立即检索

      2.1 迫切左外连接检索

3.多对一和一对多关联的检索策略。

      3.1 迫切左外连接检索

      3.2延迟检索

      3.3立即检索

3.4批量延迟检索和批量立即检索


1   类级别的检索策略

类级别可选的检索策略包括立即检索和延迟检索,默认为立即检索,即<class>元素的lazy属性为false

     立即检索

Customer.hbm.xml文件中<class name=”mypack.Customer” table=”CUSTOMER” lazy=”false”>

通过(Customer )session.load(Customer.class,new Long(1));会立即执行查询语句:

select * from CUSTOMERS wher ID=1;对于是否检索关联的Order对象要看Order的检索策略是立即检索策略,会执行查询ORDERS表的SQL语句:

select * from ORDERS wher CUSTOMER_ID=1;

     延迟检

Customer.hbm.xml文件中<class name=”mypack.Customer” table=”CUSTOMER” lazy=”true”>.当执行Sessionload()方法时,Hibernate不会立即执行查询CUSTOMERS表的select语句,仅仅返回Customer类的代理类的实例,它有以下特征:

1.  它扩展Customer 类,但是初始化它的OID属性,其他属性为null,因些占用内存少。当应用程序访问它时,才执行select语句,初始化代理类实例,变成持久化对象,但是对于getId(),因为已经初始化OID,故不要检索数据库,即执行select语句

<class>元素的lazy属性为true时,会影响Sessionload方法,如:

1.  如果要加载的Customer对象在数据库中不存在,Session.load()不抛出异常,在访问到它时(getName())才抛出异常

2.  在整个Session范围内(session.beginTransaction~session.close),都不访问Customer,以后访问就会抛出无初始化的异常

3.  用如Hibernate.initialize(customer)静态方法来显式初始化代理类实例

4.  不管Customer.hbm.xml文件的<class>元素的lazy属性是true还是false,Sessionget()find()方法在Customer类级别总是使用立即检索策略


2       一对多和多对多关联的检索策略

<set>来配置一对多关联及多对多关联,如配置CustomerOrder类的一对多关联:

<set name=”orders” inverse=”true” >

<key column=”CUSTOMER_ID” />

       <one-to-many class=”mypack.Order”/>

</set>

<set>元素有一个lazyouter-join属性。它们取不同的值的检索策略如图:

lazy属性

outer-join属性

检索策略

false

false

立即检索,这是默认策略

false

true

迫切左外连接检索

true

false

 采用延迟检索

true

true

没有任何意义(矛盾的设置)

Customer类中定义了一个java.util.Set集合类型的orders属性,不管有没有设置延迟检索策略,Session的检索方法在为Customer对象的orders属性赋值时,总是引用集合代理类的实例

  迫切左外连接检索

<set name=”orders” outer-join=”true”>

当执行session.get(Customer.class,new Long(1));时会用表连接格式检索关联的Order     .语句为:...CUSTOMERS left outer join ORDERS on … where CUSTOMERS.ID=1,但是      find()方法无作用,find仍然会用简单的select语句检索

   立即检索

       一对多关联的默认检索策略为立即检索,如代码:

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

       Set orders=customer.getOrders();

       Iterator orderIterator=orders.iterator();

       tx.commit();

       对于Customer对象采用类级别的立即检索策略,对象和Customer关联的Order对象, 用一对多关联级别的立即检索策略.因此Hibernate执行以下select语句

       select * from CUSTOMERS where ID=1

       select * from ORDERs where CUSTOMER_ID=1

      延迟检索

       <set name=”orders” lazy=”true”>

       这样运行Sessionget()方法时,仅立即执行检索Customer对象的select语句,对于orders 属性,引用的是集合代理类实例.在程序访问它时,如调用orders.getIterator(),Hibernate 初始化这个集合类实例,执行select * from ORDERS where CUSTOMER_ID=1


3      多对一和一对一关联的检索策略

       在映射文件中<many-to-one><one-to-one>用来设置多对一和一对一关联关系,    Order.hbm.xml文件中,Order类与Customer类的多对一关联,如:

       <many-to-one name=”customer” column=”CUSTOMER_ID” class=”mypack.Custome”/>

       <many-to-one>有一个outer-join属性,它有三个值:

1.  auto:默认值,如果关联的Customer的映射文件<class>lazytrue,就延迟检索Customer对象,否则采用迫切左外连接检索策略

2.  true:Customer采用迫切左外连接检索策略

3.  false:不用迫切连接检索Customer对象,看它的<class>lazy的值来决定检索策略

多对一,要看一的映射文件 (Customer的映射文件)

    迫切左外连接检索

       Order.hbm.xml文件中<many-to-one>outer-join属性为true.这时执行:

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

1.因为检索策略对get()方法无效(find()也是),因此立即检索Order对象

2.因为<many-to-one>outer-join属性为true.因此用外连接检索Customer对象

3.根据Customer的映射文件配置的策略,Order对象检索.总的执行语句为:

select * from ORDERS left outer join CUSTOMERS on ….where ORDERS.ID=1

select * from ORDERS where CUSTOMER_ID=1

如果Customer.hbm.xml文件中<set>outer-join属性为true,那么检索Customer而触发检索Order对象也用迫切左外连接.语句为:

select * from ORDES o1 left outer join CUSTOMERS c1 on…left outer join ORDERS o2….如果select语句的外连接表数目太多,会影响检索性能,此时可以通过Hibernate配置文件中的hibernate.max_fetch_depth属性来控制连接深度,如果设为1,语句就变成:

select * from ORDERS left outer join CUSTOMERS on ….where ORDERS.ID=1

select * from ORDERS where CUSTOMER_ID=1

     延迟检索

       如果希望检索Order对象时,延迟检索关联的Customer对象,要把Customer.hbm.xml.         <class lazy=”true”>Order.hbm.xml<many-to-one outer-join=”auto/false”>。如:

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

       Customer customer =order.getCustomer();//返回代理类实例的引用

       customer.getName();//检索custome即初始化customer类,并返过来又检索ORDERS

       tx.commit();

       对于一对一关联,如果使用延迟加载策略要设置constrained属性如:

       <one-to-one name=”customer” class=”mypack.Customer” constrained=”true”/>

                  立即检索

       Order.hbm.xml<many-to-one>元素的outer-join=falseCustomer.hbm.xml<class>      lazy=”false”。这个会对Customer采用立即检索策略。如:

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

       运行get()立即检索Order和与它关联的Customer,执行:

       select * from ORDERS where ID=1;//立即检索Order

       select * from CUSTOMERS where ID=1;//检索与Order关联的Customer

       select * from ORDERS where CUSTOMER_ID=1;//检索与Customer关联的Order

4            批量延迟检索和批量立即检索

       批量检索的目的是减少SQL语句,提高检索性能

   批量延迟检索

List orderLists=session.find(“from Order as c”);
Iterator orderIterator=orderLists.iterator();
 
Order order1=(Order)orderIterator.next();
Order order2=(Order)orderIterator.next();
Order order3=(Order)orderIterator.next();
Order order4=(Order)orderIterator.next();
 
Customer customer1=order1.getCustomer();
if(customer1!=null)customer1.getName();
Customer customer2=order2.getCustomer();
if(customer2!=null)customer2.getName();
Customer customer3=order3.getCustomer();
if(customer3!=null)customer3.getName();
Customer customer4=order4.getCustomer();
if(customer4!=null)customer4.getName();

检索Orderfind()方法,检索策略无效,因此立即检索Order对象。执行:

select * from ORDERS;

假定Customerlazy=”true”,就延迟检索Customer,只要ORDERSCUSTOMER_ID不为null,就创建一个Customer代理类实例给Order对象,它的OIDCUSTOMER_ID相同。当执行customer1.getName()时,才初始化OID1CUstomer代理类实例,执行完上向的代码要执行四条查询CUSTOMERS表的select语句(同一个OIDCustomer代理实例初始一次),为了减少语句。可以设置Customer.hbm.xml文件中的<class>元素的batch-size属性:

<class name=”nypack.Customer” table=”CUSTOMERS” lazy=”true” batch-size=”3”>这样就可以一下子初始化三个不同OID的代理类实例。它执行的语句如:

select * from CUSTOMERS wher ID=1 or ID=2 or ID=3 ,如果batch-size值过大,会导致延迟加载失去意义

     批量立即检索

假如Customer.hbm.xml中的<class…batch-size=”4” lazy=”false”>,Order.hbm.xml文件中的<many-to-one outer-join=”false”>那么采用立即检索。如:

List orderLists=session.find(“from Order as c”);

会对与Order关联的Customer采用批量立即检索,对与Customer关联的Order也采用批量立即检索.总执行语句如:

select * from ORDERS;

select * from CUSTOMERS where ID=1 or ID=2 or ID=3 or ID=4;

select * from ORDERS where CUSTOMER_ID=1 or CUSTOMER_ID=2 or ………..

Hibernate对迫切左外连接检索的限制。

       过多的一对多关联外连接,会检索出大量数据,影响性能,在Hibernate2.x对迫切外连 接有以下限制

1.         在一个select 语句中只允许包含一个一对多关联或多对多关联的迫切左外连接

2.         在一个select 语句中允许包含多个多对一关联或一对一关联的迫切左外连接

例子略

在应用程序是显式指定迫切左外连接检索策略

       映射文件中设定的检索策略是固定的,要么是延迟检索,要么是立即检索,要么是外连       接检索,但程序逻辑是变化的,因此产生了在程序中显式设置检索策略,覆盖映射文件    的检索策略, HQL没有显式指定延迟检索策略而QBCP324,如:

       session.find(“from Customer as c left join fetch c.orders  where c.id=1”) ;执行的SQL语句 :select * from CUSTOMERS left outer join ORDERS on …..where CUSTOMERS.ID=1

三种策略的优缺点

      

检索策略

优点

缺点

立即检索

初始化对象,可以方便访问

select 语句数目多;可能加载不需要访问的对象,浪费内存空间

延迟检索

避免加载不需要访问的对象,提高性能,节省内存空间

访问对象要对代理类实例初始化

迫切左外连接检索

初始化对象,方便访问;使用外连接,减少select语句

可能加载不需要访问的对象,浪费内存空间;检索语句复杂,影响性能

       要不断调节检索策略,在减少select语句数目和减少select语句复杂度之间找到平衡点,      以获得最佳性能



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值