Hibernate檢索方式的分類web
Hibernate的檢索方式主要有5種,分別爲導航對象圖檢索方式、OID檢索方式、HQL檢索方式、QBC檢索方式和SQL檢索方式。下面對這5中檢索方式的使用進行詳解。spring
1. 對象圖導航檢索sql
對象圖導航檢索方式是根據已經加載的對象,導航到他的關聯對象。它利用類與類之間的關係來檢索對象。譬如要查找一個聯繫人對應的客戶,就能夠由聯繫人對象自動導航找到聯繫人所屬的客戶對象。固然,前提是必須在對象關係映射文件上配置了多對一的關係。其檢索方式以下所示:數據庫
LinkMan linkMan = session.get(LinkMan.class, 1l);session
Customer customer = linkMan.getCustomer();app
2. OID 檢索方式dom
OID檢索方式主要指用Session的get()和load()方法加載某條記錄對應的對象。以下面兩種加載客戶對象的方式,就是OID檢索方式,具體以下:函數
Customer customer = session.get(Customer.class, 1l);學習
Customer customer1 = session.load(Customer.class, 1l);測試
3. HQL檢索
HQL(Hibernate Query Language)是面向對象的查詢語言,它和SQL查詢語言有些類似,但它使用的是類、對象和屬性的概念,而沒有表和字段的概念。在Hibernate提供的各類檢索方式中,HQL是官方推薦的查詢語言,也是使用最普遍的一種檢索方式,它具備以下功能。
Hibernate提供的Query接口是專門的HQL查詢接口,它可以執行各類複雜的HQL查詢語句,完整的HQL語句結構以下:
select...from...where...group by...having...order by ... asc/desc
能夠HQL查詢很是相似於表中SQL查詢。一般狀況下,當檢索數據表中的全部記錄時,查詢語句中能夠省略select關鍵字,示例以下所示:
String hql = "from Customer";
若是執行該查詢語句,則會返回應用程序中的全部Customer對象。
須要注意的是:Customer是類名,而不是表名,類名須要區分大小寫,而關鍵字from不區分大小寫。
3.1 基本檢索
1 @Test 2 public void test1() { 3 // HQL基本檢索 4 Transaction tx = session.beginTransaction(); 5 6 // 基本查詢 7 Query query = session.createQuery("from Customer"); 8 List<Customer> custList = query.list(); 9 for(Customer c : custList) { 10 System.out.println(c); 11 } 12 tx.commit(); 13 }
3.2 條件檢索
1 @Test 2 public void test2() { 3 // 條件查詢 4 Transaction tx = session.beginTransaction(); 5 Query query = session.createQuery("from Customer order by cust_id desc"); 6 List<Customer> custList = query.list(); 7 for(Customer c : custList) { 8 System.out.println(c); 9 } 10 tx.commit(); 11 }
1 @Test 2 public void test3() { 3 // 按位置綁定參數 4 Transaction tx = session.beginTransaction(); 5 Query query = session.createQuery("from Customer where cust_id=?"); 6 // query.setInteger(0, 1); 7 query.setParameter(0, 1l); 8 List<Customer> list = query.list(); 9 for(Customer c: list) { 10 System.out.println(c); 11 } 12 tx.commit(); 13 }
1 @Test 2 public void test4() { 3 // 按名稱綁定參數 4 Transaction tx = session.beginTransaction(); 5 Query query = session.createQuery("from Customer where cust_id=:name"); 6 // query.setInteger(0, 1); 7 query.setParameter("name", 1l); 8 List<Customer> list = query.list(); 9 for(Customer c: list) { 10 System.out.println(c); 11 } 12 tx.commit(); 13 }
1 @Test 2 public void test5() { 3 // 分頁查詢 4 Transaction tx = session.beginTransaction(); 5 Query query = session.createQuery("from Customer"); 6 query.setFirstResult(0); 7 query.setMaxResults(1); 8 List<Customer> cusList = query.list(); 9 for(Customer c: cusList) { 10 System.out.println(c); 11 } 12 tx.commit(); 13 }
1 @Test 2 public void test6() { 3 // 統計檢索 4 Transaction tx = session.beginTransaction(); 5 Query query = session.createQuery("select count(*) from Customer"); 6 Long num = (Long) query.uniqueResult(); 7 System.out.println(num); 8 tx.commit(); 9 }
1 @Test 2 public void test7() { 3 // 投影查詢 4 Transaction tx = session.beginTransaction(); 5 //投影查詢一列 6 Query query = session.createQuery("select cust_name from Customer"); 7 List<String> names = query.list(); 8 for(String s : names) { 9 System.out.println(s); 10 } 11 //投影查詢多列 12 Query query1 = session.createQuery("select cust_id, cust_name from Customer"); 13 List<Object[]> cs = query1.list(); 14 for(Object[] o : cs) { 15 System.out.println(Arrays.toString(o)); 16 } 17 tx.commit(); 18 }
4. QBC檢索
QBC(Query By Criteria)是Hibernate提供的另外一種檢索對象的方式,它主要有Criteria接口、Criterion接口和Expression類組成。Criteria接口是HibernateAPI中的一個查詢接口,它須要由session進行建立。
Criterion是Criteria的查詢條件,在Criteria中提供了add(Criterion criterion)方法添加查詢條件。使用QBC檢索對象的示例代碼,以下所示:
1 @Test 2 public void test1() { 3 Transaction tx = session.beginTransaction(); 4 criteria = session.createCriteria(Customer.class); 5 // 設定查詢條件 6 criteria.add(Restrictions.eq("cust_id", 1l)); 7 // 獲取查詢結果 8 List<Customer> list = criteria.list(); 9 System.out.println(list); 10 tx.commit(); 11 }
QBC檢索是使用Restrictions對象編寫查詢條件的,在Restrictions類中提供了大量的靜態方法來建立查詢條件。其經常使用的方法如表所示:
方法名 | 說明 |
Restrictions.eq | 等於 |
Restrictions.allEq | 使用Map,使用key/value進行多個等於的比較 |
Restrictions.gt | 大於> |
Restrictions.ge | 大於等於>= |
Restrictions.lt | 小於 |
Restrictions.le | 小於等於<= |
Restrictions.between | 對應SQL的between子句 |
Restrictions.like | 對應SQL的like子句 |
Restrictions.in | 對應SQL的IN子句 |
Restrictions.and | and關係 |
Restrictions.or | or關係 |
Restrictions.sqlRestriction | SQL限定查詢 |
4.1 基本檢索
1 @Test 2 public void test2() { 3 Transaction tx = session.beginTransaction(); 4 Criteria criteria = session.createCriteria(Customer.class); 5 // SimpleExpression restrictions = Restrictions.eq("cust_id", 1l); 6 // criteria.add(restrictions); 7 List<Customer> list = criteria.list(); 8 for(Customer c : list) { 9 System.out.println(c); 10 } 11 tx.commit(); 12 }
4.2 條件檢索
1 @Test 2 public void test3() { 3 // 條件檢索 4 Transaction tx = session.beginTransaction(); 5 Criteria criteria = session.createCriteria(Customer.class); 6 // criteria.add(Restrictions.eq("cust_name", "test1")); 7 // criteria.add(Restrictions.like("cust_name", "%te%")); 8 criteria.add(Restrictions.gt("cust_id", 1l)); 9 List<Customer> custList = criteria.list(); 10 for(Customer c : custList) { 11 System.out.println(c); 12 } 13 tx.commit(); 14 }
4.3 分頁檢索
1 @Test 2 public void test4() { 3 // 分頁檢索 4 Transaction tx = session.beginTransaction(); 5 Criteria criteria = session.createCriteria(Customer.class); 6 criteria.setFirstResult(0); 7 criteria.setMaxResults(2); 8 List<Customer> custList = criteria.list(); 9 for(Customer c : custList) { 10 System.out.println(c); 11 } 12 tx.commit(); 13 }
4.4 排序檢索
1 @Test 2 public void test5() { 3 // 排序檢索 4 Transaction tx = session.beginTransaction(); 5 Criteria criteria = session.createCriteria(Customer.class); 6 criteria.addOrder(Order.desc("cust_id")); 7 List<Customer> custList = criteria.list(); 8 for(Customer c : custList) { 9 System.out.println(c); 10 } 11 tx.commit(); 12 }
4.5 統計檢索
1 @Test 2 public void test6() { 3 // 統計檢索 4 Transaction tx = session.beginTransaction(); 5 Criteria criteria = session.createCriteria(Customer.class); 6 criteria.setProjection(Projections.rowCount()); 7 Long count = (Long) criteria.uniqueResult(); 8 System.out.println(count); 9 tx.commit(); 10 }
4.6 離線條件檢索
DetachedCriteria翻譯爲離線條件查詢,由於它是能夠脫離Session來使用的一種條件查詢對象,咱們都知道Criteria對象必須由Session對象來建立。那麼也就是說必須先有Session才能夠生成Criteria對象。而DetachedCriteria對象能夠在其餘層對條件進行封裝。
這個對象也是比較有用的,尤爲在SSH整合之後這個對象常常會使用。它的主要優勢是作一些特別複雜的條件查詢的時候,每每會在WEB層向業務層傳遞不少的參數,業務層又會將這些參數傳遞給DAO層。最後在DAO中拼接SQL完成查詢。有了離線條件查詢對象後,那麼這些工做均可以不用關心了,咱們能夠在WEB層將數據封裝好,傳遞到業務層,再由業務層傳遞給DAO完成查詢。
咱們能夠先簡單的測試一下離線條件查詢對象,而後具體的使用咱們會在後期整合中使用,到那時會更加體會出它的優點。
1 @Test 2 public void test7() { 3 // 離線條件查詢:DetachedCriteria(SSH整合常用) 4 // 能夠脫離Session設置參數 5 6 // 得到一個離線條件查詢對象 7 DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class); 8 detachedCriteria.add(Restrictions.eq("cust_name", "test1")); 9 Transaction tx = session.beginTransaction(); 10 List<Customer> list = detachedCriteria.getExecutableCriteria(session).list(); 11 for(Customer c : list) { 12 System.out.println(c); 13 } 14 tx.commit(); 15 }
5. 本地SQL檢索方式
採用HQL或QBC檢索方式時,Hibernate生成標準的SQL查詢語句,適用於全部的數據庫平臺,所以這兩種檢索方式都是跨平臺的。但有的應用程序可能須要根據底層數據庫的SQL方言,來生成一些特殊的查詢語句。在這種狀況下,能夠利用Hibernate提供的SQL檢索方式。使用SQL檢索方式檢索對象的示例代碼,以下所示:
SQLQuery sqlQuery = session.createSQLQuery("select id,name,age,city from customer");
在這,SQL的檢索方式咱們不作太多的介紹。以前不管咱們使用的是HQL或是QBC或是SQL其實都是單表的查詢,而實際的開發中咱們每每須要多個表的聯合查詢才能夠得到咱們想要的數據。
6. Hibernate的多表查詢
在作多表查詢以前,咱們須要先來回顧下使用SQL是如何完成多表的查詢的。在學習SQL語句的時候進行多表聯合查詢通常都會採用鏈接查詢,那麼咱們就來回顧一下SQL中的多表的聯合查詢。
6.1 鏈接查詢
交叉鏈接返回的結果是被鏈接的兩個表中全部數據行的笛卡爾積,也就是返回第一個表中符合查詢條件的數據行數乘以第二個表中符合查詢條件的數據行數,例如department表中有四個部門,employee表中有四個員工,那麼交叉鏈接的結果就是4*4=16條數據。
交叉鏈接的語法格式以下:
select * from 表1 CROSS JOIN 表2;
也能夠寫爲以下格式:
SELECT * from 表1, 表2;
從上述描述狀況能夠看出,交叉鏈接的結果就是兩個表中全部數據的組合。須要注意的是,在實際開發中這種業務需求不多見的,通常不會使用交叉鏈接,而是使用具體的條件對數據進行有目的的查詢。
內鏈接(INNER JOIN)又稱簡單鏈接或天然鏈接,是一種常見的鏈接查詢。內鏈接使用比較運算符對兩個表中的數據進行比較,並列出與鏈接條件匹配的數據行,組合成新的記錄,也就是說在內鏈接查詢中,只有知足條件的記錄才能出如今查詢結果中。內鏈接查詢的語法格式以下所示:
select 查詢字段 from 表1 [INNER] JOIN 表2 on 表1.關係字段=表2.關係字段
在上述語法格式中,INNER JOIN用於鏈接兩個表,ON來指定鏈接條件,其中INNER能夠省略。內鏈接其實還能夠細分爲以下兩類:
select * from 表1, 表2 where 表1.關係字段 = 表2.關係字段;
select * from 表1 inner join 表2 on 表1.關係字段 = 表2.關係字段;
select * from 表1 join 表2 on 表1.關係字段 = 表2.關係字段;
前面講解的內鏈接查詢中,返回的結果只包含符合查詢條件和鏈接條件的數據,然而有時還須要包含沒有關聯的數據,即返回查詢結果中不只包含符合條件的數據,並且還包括左表(左鏈接或左外鏈接)、右表(右鏈接或右外鏈接)或兩個表(全外鏈接)中的全部數據,此時就須要使用外鏈接查詢,外鏈接分爲左鏈接和右鏈接,外鏈接的語法格式以下:
select 所查字段 from 表1 left | rigth [outer] JOIN 表2 on 表1.關係字段 = 表2.關係字段 where 條件
外鏈接的語法格式和內鏈接相似,只不過使用的是LEFT JOIN、RIGHT JOIN關鍵字,其中關鍵字左邊的表被稱爲左表,關鍵字右邊的表被稱爲右表。
在使用左鏈接和右鏈接查詢時,查詢結果是不一致的,具體以下:
6.2 LEFT JOIN(左鏈接): 返回包括左表中的全部記錄和右表中符合鏈接條件的記錄。
select * from 表1 left outer join 表2 on 表1.關係字段=表2.關係字段;
select * from A left join 表2 on 表1.關係字段 = 表2.關係字段;
6.3 RIGHT JOIN(右鏈接):返回包括右表中的全部記錄和左表中符合鏈接條件的記錄。
select * from 表1 right outer join 表2 on 表1.關係字段 = 表2.關係字段;
select * from A right join 表2 on 表1.關係字段 = 表2.關係字段;
SQL語句的鏈接查詢咱們會寫了,那麼Hibernate中的HQL如何進行鏈接查詢呢?
6.2 HQL鏈接查詢
Hibernate進行多表查詢與SQL實際上是很類似的,可是HQL會在原來SQL分類的基礎上又多出來一些操做。
HQL的多表鏈接查詢的分類以下:
其實,這些鏈接查詢語法大體都是一致的,就是HQL查詢的是對象而SQL查詢的是表:
SQL鏈接查詢:select * from cst_customer c inner join cst_linkman l on c.cust_id = l.lkm_cust_id;
HQL鏈接查詢:from Customer c inner join c.linkmans
Hibernate懶加載策略
在Hibernate中,<many-to-one.../>中的lazy默認爲proxy。這樣hibernate在數據庫中查詢數據時事不會把關聯的對象查出來的,而是保存一個得到該值得方法:getXxxx()。當咱們須要使用這個值的時候,也就是使用getXxx()方法來調用的時候,Hibernate就會利用這個方法從數據庫中獲取相應的數據。可是很不幸,咱們的session早就關閉了。
這是由於Hibernate的懶加載策略,在Hibernate中是使用sessionFactory來管理session,咱們每進行一次數據庫操做時都會新建一個session對象,當咱們操做完成後,hibernate就會在dao層當即關閉該session。這樣作就能夠嚴格控制session,避免出現低級錯誤。
下面給出三種解決辦法,我的認爲第二種比較好
一、把lazy設成false。這個是最簡單的辦法,我的認爲也是比較笨的方法。由於這是在用效率做爲代價。
二、使用OpenSessionInViewFilter。這種方法是將session交給servlet filter來管理,每當一個請求來以後就會開啓一個session,只有當響應結束後纔會關閉。以下:
1 <filter-name>hibernateFilter</filter-name> 2 <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class> 3 </filter 4 <filter-mapping> 5 <filter-name>hibernateFilter</filter-name> 6 <url-pattern>/*</url-pattern> 7 </filter-mapping>
上面的配置文件時在web.xml中配置的。
三、將hibernate的抓起策略改成join。也就是是left join fetch或inner join fetch語法。就是在<many-to-one../>中配置lazy="false" fetch="join"便可。如:
1 <many-to-one name="worker" lazy="false" fetch="join" class="com.paixie.domain.Worker"> 2 3 <column name="positionId"></column> 4 5 </many-to-one>