轉載自:http://aumy2008.blogbus.com/logs/14096736.html
五、高級查詢技巧
2、集合過濾
延遲檢索策略――customer.getOrders().iterator() (加載關聯對象集合),這種方式的不足:
l 全部加載
l 不能排序
2種辦法可以解決上邊不足,一種是通過HQL或QBC查詢orders集合,還有一種辦法就是使用集合過濾。
集合過濾示例:
List result=session.createFilter(customer.getOrders(), "where this.price>200 order by this.price").list(); Iterator it=result.iterator(); while(it.hasNext()){ Order order =(Order)it.next(); .....}
Session的createFilter()方法用來過濾集合,它具有以下特定。
l 返回Qurey類型的實例。
l 第一個參數:指定一個持久化對象的集合,這個集合是否已經被初始化並沒有關係,但它所屬的對象必須處於持久化狀態。否則拋出異常。
l 第二個參數:指定過濾條件,它由合法的HQL查詢語句組成。
l 不管持久化對象的集合是否已經初始化,Query的list()方法都會執行SQL查詢語句,到數據庫中檢索Order對象。
l 如果對象的集合已經被初始化,爲了保證Session的緩存中不會出現OID相同的Order對象,Query的list()方法不會再創建Order對象,僅僅返回已經存在的Order對象的引用。
l 如果沒有初始化,Query的list()方法創建相應的對象,但不會初始化所給對象的集合。(僅僅取出符合條件的對象集合,是對象集合的子集)
集合過濾的幾個應用:
A、爲集合排序或設置約束條件
B、 集合分頁
C、 檢索集合中對象的某個屬性
D、檢索數據庫中與Customer對象的orders集合中的Order對象的屬性(一個或多個)相同的所有Order對象
E、 檢索Order對象的lineItems集合中LineItem對象的Item
代碼示例:
List result=session.createFilter(customer.getOrders(), " order by this.price asc") .setFirstResult(10) .setMaxResults(5) .list(); List result=session.createFilter(customer.getOrders(), "select this.orderNumber") .list(); List result=session.createFilter(customer.getOrders(), "select other from Order other where other.price=this.price") .list(); List result=session.createFilter(order.getLineItems(), "select this.item").list();
3、子查詢
HQL支持where子句中嵌入查詢語句。
from Customer c where 1<(select count(o) from c.orders o) ――相關子查詢
from Order o where o.price>(select avg(o1.price) from Order o1) 無關
關於子查詢的用法說明:
(1)、子查詢可以分爲相關子查詢和無關子查詢。
(2)、依賴底層數據庫對子查詢的支持能力。
(3)、如果子查詢語句返回多條記錄,可以用一下關鍵字來衡量。
l all:表示子查詢語句返回的所有記錄。
l any:任意一條記錄。
l some:與“any”等價。
l in:與“=any”等價。
l exists:至少返回一條記錄。
例:訂單的價格都不小於100的客戶
from Customer c where 100>all (select o.price from c.orders o)
有一條訂單的價格小於100的客戶
from Customer c where 100>any (select o.price from c.orders o)
有一條訂單的價格等於100的客戶
from Customer c where 100=some (select o.price from c.orders o)
或
from Customer c where 100=any (select o.price from c.orders o)
或
from Customer c where 100 in (select o.price from c.orders o)
至少有一條訂單的客戶
from Customer c where exsist (from c.orders)
(4)、如果子查詢語句查詢的是集合,HQL提供了所寫語法
Iterator it=session.createQurey( "from Customer c where :order in element(c.orders)") .setEntity("order",order) .list().iterator();
element(c.orders)等價於(from c.orders)
HQL提供了一族操縱集合的函數或者屬性。
l size()函數或size屬性:獲取集合中元素的數目。
l minIndex()函數或minIndex屬性:對於建立了索引的集合,獲取最小的索引。
l maxIndex()函數或maxIndex屬性:對於建立了索引的集合,獲取最大的索引。
l minElement()函數或minElement屬性:對於包含基本類型元素的集合,獲得集合中取值最小的元素。
l maxElement()函數或maxElement屬性:對於包含基本類型元素的集合,獲得集合中取值最大的元素。
l elements()函數:獲得集合中所有元素。
如:訂單數目大於零的客戶
from Customer c where c.orders.size>0
或者 from Customer c where size(c.orders)>0
4、本地SQL查詢
Hibernate本地SQL查詢提供了支持,爲了把SQL查詢返回的關係數據映射爲對象,需要在SQL查詢語句中爲字段指定別名。
String sql1 = "select cs.ID as {c.id},cs.name as {c.name} " + "from CUSTOMERS cs where cs.ID=1";Query query = session.createSQLQurey(sql1, "c", Customer.class);
或
String sql1 = "select {c.*} " + "from CUSTOMERS c where c.ID=1";Query query = session.createSQLQurey(sql1, "c", Customer.class);
多個不同的對象情況
String sql1 = "select {c.*},{o.*} from CUSTOMERS c inner join ORDERS o" + " where c.ID=o.CUSTOMER_ID"; Query query = session.createSQLQurey(sql1, new String[] { "c", "o" },new Class[] { Customer.class, Order.class });
在程序中嵌入本地SQL語句會增加維護程序代碼的難度,如果數據庫表的結構發生變化,必須修改相應的程序代碼,因此更合理的方式是把SQL查詢語句放到映射文件中:
<sql-query name="findCustomersAndOrders"><![CDATA[ select {c.*},{o.*} from CUSTOMERS c inner join ORDERS o where c.ID=o.CUSTOMER_ID ]]> <return alias="c"class="Customer"> <return alias="o"class="Order"></sql-query>
六、查詢性能優化
1、 降低訪問數據庫的頻率,減少select語句的數目。實現手段包括:
l 使用迫切左外連接或迫切內連接檢索策略。
l 對延遲加載或立即加載策略設置批量檢索數目。
l 使用查詢緩存。
2、避免多餘加載程序不需要訪問的數據。實現手段包括:
l 使用延遲檢索策略。
l 使用集合過濾。
3、 避免報表查詢數據佔用緩存。實現手段爲利用投影查詢功能,查詢出實體的部分屬性。
4、減少select語句中的字段,從而降低訪問數據庫的數據量。實現手段爲利用Query的iterate()方法。
iterate()方法:
Query接口的iterate()方法和list()方法都能執行SQL查詢語句。
list()首先檢索ID字段,然後根據ID字段到Hibernate第一緩存以及第二級緩存中查找匹配的對象,如果存在,就直接把它加入到查詢結果集中,否則就只想額外的select語句,根據ID字段數據庫中檢索該對象。
查詢緩存
查詢緩存適應以下場合:
l 在應用程序運行時經常使用的查詢語句。
l 很少對與查詢語句關聯的數據庫數據進行插入、刪除或更新操作。
查詢語句啓用查詢緩存的步驟如下:
A、配置第二級緩存。
B、 在Hibernate的hibernate.properties配置文件中設置查詢緩存屬性:
hibernate.cache.use_query_cache=true
C、啓用查詢緩存。調用Query接口的setCacheable(true)方法。
結束!