hibernate 檢索策略

來源:互聯網
上載者:User

標籤:string   null   特徵   close   初始化   引用   -o   目的   ati   

概述

  • 不浪費記憶體:當 Hibernate 從資料庫中載入 Customer 對象時, 假設同一時候載入全部關聯的 Order 對象, 而程式實際上只須要訪問 Customer 對象, 那麼這些關聯的 Order 對象就白白浪費了很多記憶體.
  • 更高的查詢效率:發送儘可能少的 SQL 陳述式


類層級的檢索策略
  • 類層級可選的檢索策略包含馬上檢索和延遲檢索, 默覺得延遲檢索
    • 馬上檢索: 馬上傳入檢索方法指定的對象
    • 延遲檢索: 延遲載入檢索方法指定的對象。在使用詳細的屬性時。再進行載入
  • 類層級的檢索策略能夠通過 <class> 元素的 lazy屬性進行設定
  • 假設程式載入一個對象的目的是為了訪問它的屬性, 能夠採取馬上檢索.
  • 假設程式載入一個持久化對象的目的是只為了獲得它的引用, 能夠採用延遲檢索。

    注意出現懶載入異常。

  • 不管 <class> 元素的 lazy 屬性是 true 還是 false, Session 的 get() 方法及 Query 的 list() 方法在類層級總是使用馬上檢索策略
  • 若 <class> 元素的 lazy 屬性為 true 或取預設值, Session 的 load()方法不會執行查詢資料表的 SELECT 語句, 僅返回代理類對象的執行個體, 該代理類執行個體有例如以下特徵:
    • 由 Hibernate 在執行時採用 CGLIB 工具動態產生
    • Hibernate 建立代理類執行個體時, 僅初始化其 OID 屬性
    • 在應用程式第一次訪問代理類執行個體的非 OID 屬性時, Hibernate 會初始化代理類執行個體


一對多和多對多的檢索策略
在對應檔裡, 用 <set> 元素來配置一對多關聯及多對多關聯關係. <set> 元素有 lazy 和 fetch 屬性
  • lazy: 主要決定 orders 集合被初始化的時機. 即究竟是在載入 Customer 對象時就被初始化, 還是在程式訪問 orders 集合時被初始化
  • fetch: 取值為 “select” 或 “subselect” 時, 決定初始化 orders 的查詢語句的形式; 若取值為”join”, 則決定 orders 集合被初始化的時機
  • 若把 fetch 設定為 “join”, lazy 屬性將被忽略
  • <set> 元素的 batch-size 屬性:用來為延遲檢索策略或馬上檢索策略設定批量檢索的數量. 批量檢索能降低 SELECT 語句的數目, 提高延遲檢索或馬上檢索的執行效能.

<set> 元素的 lazy 和 fetch 屬性




延遲檢索和增強延遲檢索
  • 在延遲檢索(lazy 屬性值為 true) 集合屬性時, Hibernate 在下面情況下初始化集合代理類執行個體 
    • 應用程式第一次訪問集合屬性: iterator(), size(), isEmpty(), contains() 等方法
    • 通過 Hibernate.initialize() 靜態方法顯式初始化

  • 增強延遲檢索(lazy 屬性為 extra): 與 lazy=“true” 類似. 主要差別是增強延遲檢索策略能進一步延遲 Customer 對象的 orders 集合代理執行個體的初始化時機:
    • 當程式第一次訪問 orders 屬性的 iterator() 方法時, 會導致 orders 集合代理類執行個體的初始化
    • 當程式第一次訪問 order 屬性的 size(), contains() 和 isEmpty() 方法時, Hibernate 不會初始化 orders 集合類的執行個體, 僅通過特定的 select 語句查詢必要的資訊, 不會檢索全部的 Order 對象

<set> 元素的 batch-size 屬性<set> 元素有一個 batch-size 屬性, 用來為延遲檢索策略或馬上檢索策略設定批量檢索的數量. 批量檢索能降低 SELECT 語句的數目, 提高延遲檢索或馬上檢索的執行效能.


用帶子查詢的 select 語句整批量初始化 orders 集合(fetch 屬性為 “subselect”)
  • <set> 元素的 fetch 屬性: 取值為 “select” 或 “subselect” 時, 決定初始化 orders 的查詢語句的形式; 若取值為”join”, 則決定 orders 集合被初始化的時機.預設值為 select
  • 當 fetch 屬性為 “subselect” 時
    • 假定 Session 緩衝中有 n 個 orders 集合代理類執行個體沒有被初始化, Hibernate 可以通過帶子查詢的 select 語句, 來批量初始化 n 個 orders 集合代理類執行個體
    • batch-size 屬性將被忽略
    • 子查詢中的 select 語句為查詢 CUSTOMERS 表 OID 的 SELECT 語句

迫切左外串連檢索(fetch 屬性值設為 “join”)
  • <set> 元素的 fetch 屬性: 取值為 “select” 或 “subselect” 時, 決定初始化 orders 的查詢語句的形式; 若取值為”join”, 則決定 orders 集合被初始化的時機.預設值為 select 
  • 當 fetch 屬性為 “join” 時:
    • 檢索 Customer 對象時, 會採用迫切左外串連(通過左外串連載入與檢索指定的對象關聯的對象)策略來檢索全部關聯的 Order 對象
    • lazy 屬性將被忽略
    • Query 的list() 方法會忽略對應檔裡配置的迫切左外串連檢索策略, 而依然採用延遲載入策略


多對一和一對一關聯的檢索策略
  • 和 <set> 一樣, <many-to-one> 元素也有一個 lazy 屬性和 fetch 屬性.

    • 若 fetch 屬性設為 join, 那麼 lazy 屬性被忽略
    • 迫切左外串連檢索策略的長處在於比馬上檢索策略使用的 SELECT 語句更少. 
    • 無代理延遲檢索須要增強持久化類的位元組碼才幹實現
  • Query 的 list 方法會忽略對應檔配置的迫切左外串連檢索策略, 而採用延遲檢索策略
  • 假設在關聯層級使用了延遲載入或馬上傳入檢索策略, 能夠設定批量檢索的大小, 以協助提高延遲檢索或馬上檢索的執行效能. 
  • Hibernate 同意在應用程式中覆蓋對應檔裡設定的檢索策略.

檢索策略小結
類層級和關聯層級可選的檢索策略及預設的檢索策略

3 種檢索策略的執行機制

對應檔裡用於設定檢索策略的幾個屬性

比較 Hibernate 的三種檢索策略




代碼具體解釋:Customer.java
package com.atguigu.hibernate.strategy;import java.util.HashSet;import java.util.Set;public class Customer {private Integer customerId;private String customerName;private Set<Order> orders = new HashSet<>();public Integer getCustomerId() {return customerId;}public void setCustomerId(Integer customerId) {this.customerId = customerId;}public String getCustomerName() {return customerName;}public void setCustomerName(String customerName) {this.customerName = customerName;}public Set<Order> getOrders() {return orders;}public void setOrders(Set<Order> orders) {this.orders = orders;}}

Order.java
package com.atguigu.hibernate.strategy;public class Order {private Integer orderId;private String orderName;private Customer customer;public Integer getOrderId() {return orderId;}public void setOrderId(Integer orderId) {this.orderId = orderId;}public String getOrderName() {return orderName;}public void setOrderName(String orderName) {this.orderName = orderName;}public Customer getCustomer() {return customer;}public void setCustomer(Customer customer) {this.customer = customer;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((orderId == null) ? 0 : orderId.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Order other = (Order) obj;if (orderId == null) {if (other.orderId != null)return false;} else if (!orderId.equals(other.orderId))return false;return true;}}

Customer.hbm.xml
<?xml version="1.0"?

><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.atguigu.hibernate.strategy"> <class name="Customer" table="CUSTOMERS" lazy="true" batch-size="5"> <id name="customerId" type="java.lang.Integer"> <column name="CUSTOMER_ID" /> <generator class="native" /> </id> <property name="customerName" type="java.lang.String"> <column name="CUSTOMER_NAME" /> </property> <set name="orders" table="ORDERS" inverse="true" order-by="ORDER_NAME DESC" lazy="true" batch-size="2" fetch="subselect"> <key column="CUSTOMER_ID"></key> <one-to-many class="Order"/> </set> </class> </hibernate-mapping>


Order.hbm.xml
<?xml version="1.0"?

><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.atguigu.hibernate.strategy"> <class name="Order" table="ORDERS"> <id name="orderId" type="java.lang.Integer"> <column name="ORDER_ID" /> <generator class="native" /> </id> <property name="orderName" type="java.lang.String"> <column name="ORDER_NAME" /> </property> <many-to-one name="customer" class="Customer" column="CUSTOMER_ID"lazy="false"fetch="join"></many-to-one> </class></hibernate-mapping>


package com.atguigu.hibernate.strategy;import java.util.List;import org.hibernate.Hibernate;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.hibernate.service.ServiceRegistry;import org.hibernate.service.ServiceRegistryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;public class HibernateTest {private SessionFactory sessionFactory;private Session session;private Transaction transaction;@Beforepublic void init(){Configuration configuration = new Configuration().configure();ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())                            .buildServiceRegistry();sessionFactory = configuration.buildSessionFactory(serviceRegistry);session = sessionFactory.openSession();transaction = session.beginTransaction();}@Afterpublic void destroy(){transaction.commit();session.close();sessionFactory.close();}@Testpublic void testMany2OneStrategy(){//Order order = (Order) session.get(Order.class, 1);//System.out.println(order.getCustomer().getCustomerName()); List<Order> orders = session.createQuery("FROM Order o").list();for(Order order: orders){if(order.getCustomer() != null){System.out.println(order.getCustomer().getCustomerName()); }}//1. lazy 取值為 proxy 和 false 分別代表相應相應的屬性採用延遲檢索和馬上檢索//2. fetch 取值為 join, 表示使用迫切左外串連的方式初始化 n 關聯的 1 的一端的屬性//忽略 lazy 屬性. //3. batch-size, 該屬性須要設定在 1 那一端的 class 元素中: //<class name="Customer" table="CUSTOMERS" lazy="true" batch-size="5">//作用: 一次初始化 1 的這一段代理對象的個數. }@Testpublic void testSetFetch2(){Customer customer = (Customer) session.get(Customer.class, 1);System.out.println(customer.getOrders().size()); }@Testpublic void testSetFetch(){List<Customer> customers = session.createQuery("FROM Customer").list();System.out.println(customers.size()); for(Customer customer: customers){if(customer.getOrders() != null)System.out.println(customer.getOrders().size());}//set 集合的 fetch 屬性: 確定初始化 orders 集合的方式. //1. 預設值為 select. 通過正常的方式來初始化 set 元素//2. 能夠取值為 subselect. 通過子查詢的方式來初始化全部的 set 集合. 子查詢//作為 where 子句的 in 的條件出現, 子查詢查詢全部 1 的一端的 ID. 此時 lazy 有效.//但 batch-size 失效. //3. 若取值為 join. 則//3.1 在載入 1 的一端的對象時, 使用迫切左外串連(使用左外連結進行查詢, 且把集合屬性進行初始化)的方式檢索 n 的一端的集合屬性//3.2 忽略 lazy 屬性.//3.3 HQL 查詢忽略 fetch=join 的取值}@Testpublic void testSetBatchSize(){List<Customer> customers = session.createQuery("FROM Customer").list();System.out.println(customers.size()); for(Customer customer: customers){if(customer.getOrders() != null)System.out.println(customer.getOrders().size());}//set 元素的 batch-size 屬性: 設定一次初始化 set 集合的數量. }@Testpublic void testOne2ManyLevelStrategy(){Customer customer = (Customer) session.get(Customer.class, 1);System.out.println(customer.getCustomerName()); System.out.println(customer.getOrders().size());Order order = new Order();order.setOrderId(1);System.out.println(customer.getOrders().contains(order));Hibernate.initialize(customer.getOrders()); //---------------set 的 lazy 屬性------------------//1. 1-n 或 n-n 的集合屬性預設使用懶載入檢索策略.//2. 能夠通過設定 set 的 lazy 屬性來改動預設的檢索策略. 默覺得 true//並不建議設定為  false. //3. lazy 還能夠設定為 extra. 增強延遲檢索. 該取值會儘可能的延遲集合初始化的時機!}@Testpublic void testClassLevelStrategy(){Customer customer = (Customer) session.load(Customer.class, 1);System.out.println(customer.getClass()); System.out.println(customer.getCustomerId()); System.out.println(customer.getCustomerName()); }}


hibernate 檢索策略

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.