7.Hibernate 檢索
1.Hibernate檢索方式
檢索方式簡介:
導航物件圖檢索方式:
根據已經載入的物件,導航到其他物件。
OID檢索方式:
按照物件的OID來檢索物件。Session 的 get() 和 load() 方法提供了這種功能。
HQL檢索方式:
使用面向物件的HQL查詢語言。
QBC檢索方式:
使用QBC(Query By Criteria)API來檢索物件。這種API封裝了基於字串形式的查詢語句,提供了更加面向物件的介面。
本地SQL檢索方式:
使用本地資料庫的SQL查詢語句。
HQL簡介:
HQL是一種面向物件的查詢語言,和SQL查詢語言有些類似。
在Hibernate提供的各種檢索方式中,HQL是使用最廣的一種檢索方式。
Query介面是HQL查詢介面,提供各種查詢功能。
HQL實體檢索:
where 子句。
where 子句中給出的是類的屬性名而不是資料庫表字段名,其中屬性名必須區分大小寫。
String hql = "from User where userName='張三'"; Query query = session.createQuery(hql); List userList = query.list();
HQL支援的各種運算子:
程式中指定的連線型別 |
HQL運算子 |
比較運算子 |
=、<>、>=、<=、>、<、is null、is not null |
範圍運算子 |
in、not in、between…and、not between…and |
字串模式匹配運算子 |
like |
邏輯運算子 |
and、or、not |
HQL使用別名查詢:
HQL檢索一個類的例項時,如果查詢語句的其它地方需要引用它,可以給類指定一個別名。
as 關鍵字用來指定別名,as 關鍵字也可以省略。
from User where userName='張三' from User as u where u.userName='張三' from User u where u.userName='張三'
HQL支援多型查詢:
多型查詢指查詢出當前類以及所有子類的例項。
Employee 有兩個子類:HourlyEmployee 和 SalariedEmployee。
Query query = session.createQuery("from Employee"); List employeeList = query.list();
HQL檢索單個物件:
HQL查詢返回結果方法:
list():返回List型別的查詢結果,返回所有滿足條件的物件。
uniqueResult():返回單個物件。
Query query = session.createQuery("from User u where u.userName='張三'"); User user = (User)query.uniqueResult();
HQL分組與排序:
order by 字句:
from User u order by u.userName from User u order by u.userName desc from User u order by u.userName, u.id desc
group by 子句:
select count(u) from User u group by u.age
having子句:
select count(u) from User u group by u.age having count(u)<4
HQL引數繫結:
前述HQL中查詢引數均直接在HQL中表達。
String hql = "from User as u where u.userName='張三'"; String hql = "from User as u where u.userName =" + name;
缺陷:
程式碼更加零亂,可讀性降低;
難以進行效能優化;
引入額外的安全風險。
在HQL查詢語句中按照引數位置繫結引數。
setParameter() 引數位置從0開始。
String hql = "from User u where u.userName=?"; Query query = session.createQuery(hql); query.setParameter(0, "張三"); List<User> userList = query.list();
在HQL查詢語句中按引數名稱繫結引數。
String hql = "from User u where u.userName=:name"; Query query = session.createQuery(hql); query.setParameter("name", "張三"); List<User> userList = query.list();
HQL的繫結引數方法:
setParameter() 繫結任意型別的引數。
setProperties() 用於把命名引數與一個物件的屬性值繫結,並且引數名稱要與物件屬性名稱一致。
HQL實體更新:
不使用HQL的實體更新;
Transaction tx = session.beginTransaction(); User user = (User) session.get(User.class, 1); user.setUserName("Tom"); tx.commit();
HQL實現實體更新的方式。
Transaction tx = session.beginTransaction(); String hql = "update User set userName='Tom' where id=2"; Query query = session.createQuery(hql); int ret = query.executeUpdate(); tx.commit();
HQL實體刪除:
Transaction tx = session.beginTransaction(); String hql = "delete from User where id = 1"; Query query= session.createQuery(hql); int ret = query.executeUpdate(); tx .commit();
HQL子查詢:
HQL支援在 where 子句中嵌入子查詢語句,並且子查詢語句必須放在括號內。
查詢訂單數量大於0的所有使用者:
from User u where 0<(select count(o) from u.orderSet o)
對應的SQL語句:
select * from user u where 0<(select count(o) from orders o where u.id=o.userId )
HQL子查詢說明以下幾點:
子查詢分為相關子查詢和無關子查詢;
相關子查詢:子查詢語句引用了外層查詢語句定義的別名。
無關子查詢:子查詢語句沒有引用外層查詢語句定義的別名。
HQL子查詢功能依賴於底層資料庫對子查詢的支援;
HQL子查詢返回的是多條記錄,使用以下關鍵字量化。
all、any、some、in、exists。
如果HQL子查詢的是集合,HQL提供了一組操作集合的函式。
size(),獲得集合中元素的個數;
maxIndex(),對於建立索引的集合,獲得最大索引值;
minIndex(),對於建立索引的集合,獲得最小索引值;
elements(),獲得集合中所有元素。
HQL分頁查詢:
做批量查詢時,如果資料量很大就需要分頁功能,HQL提供了用於分頁查詢的方法:
setFirstResult(int firstResult)—設定從哪個物件開始檢索。
setMaxResult(int maxResult)—設定一次檢索物件的數目。
HQL引用查詢 :
引用查詢指在對映檔案中定義查詢語句。
在O/R對映xml檔案中,用與<calss>元素同級的<queryname="XXX">元素定義一個HQL查詢語句。
<query name="findUser">from User</query>
程式中通過session.getNamedQuery("XXX")呼叫對應的HQL。
Query query = session.createNamedQuery("findUser", User.class); List userList = query.list();
Qauery By Criteria(QBC) 可以看作是傳統SQL的物件化表示。
它主要由Criteria介面,Criterion介面,Expression類組成。
QBC表示式:
檢索姓名為 Erica 的所有使用者。
Criteria criteria=session.createCriteria(User.class); Criterion c1= Restrictions.eq("userName", "張三"); criteria.add(c1); List result = criteria.list();
步驟:
呼叫 Session 的 createCriteria() 建立 Criteria 例項;
通過 Restrictions 設定查詢條件;
呼叫 Criteria 例項的 list() 方法執行查詢。
運算型別 |
方法 |
描述 |
比較運算子 |
Restrictions.eq |
等於 |
Restrictions.ne |
不等於 |
|
Restrictions.gt |
大於 |
|
Restrictions.ge |
大於等於 |
|
Restrictions.lt |
小於 |
|
Restrictions.le |
小於等於 |
|
Restrictions.isNull |
等於空值 |
|
Restrictions.isNotNull |
非空值 |
運算型別 |
方法 |
描述 |
範圍運算子 |
Restrictions.in |
等於列表中的某個值 |
Restrictions.not(Restrictions.in) |
不等於列表中的任意值 |
|
Restrictions.between |
大於等於值1小於等於值2 |
|
字串模糊匹配 |
Restrictions.like |
字串模糊匹配 like |
邏輯運算子 |
Restrictions.and |
邏輯與 |
Restrictions.or |
邏輯或 |
|
Restrictions.not |
邏輯非 |
本地SQL查詢:
HQL 和 QBC 查詢,Hibernate 會生成標準的 SQL 語句適合不同的資料庫平臺。
有時需要根據底層資料庫生成特殊的 SQL 查詢語句, Hibernate 對本地 SQL 查詢提供了內建支援。
查詢所有的使用者資訊:
String sql = "select * fromuser"; NativeQuery query = session.createNativeQuery(sql, User.class); List list = query.list();
步驟:
呼叫session.createNativeQuery()建立NativeQuery例項,並指定查詢的實體型別;
呼叫NativeQuery例項的list() 方法執行查詢(如果查詢單個物件,呼叫uniqueResult() )。
2.Hibernate檢索策略
檢索策略:
立即檢索:立即載入檢索方法指定的物件。
載入多於需要的物件白白浪費記憶體空間;
select 語句數量多,頻繁訪問資料庫,影響系統性能。
延遲檢索:延遲載入檢索方法指定的物件。
避免多載入應用程式不需要訪問的資料物件。
迫切左外連線檢索:利用SQL外連線查詢功能載入檢索方法指定物件。
減少執行select語句的數量,減少資料庫訪問,提高系統性能。
檢索執行分析:
Query query = session.createQuery("from User"); List userList = query.list();
Hibernate在執行檢索方法時,要獲取以下兩種資訊:
類級別的檢索策略:Hibernate檢索方法指定的檢索物件(User)的檢索策略;
關聯級別的檢索策略:與檢索方法指定的檢索物件相關聯的物件(Order)的檢索策略。
類級別和關聯級別可選的檢索策略:
檢索策略的作用域 |
可選的檢索策略 |
預設的檢索策略 |
影響到的檢索方法 |
類級別 |
立即檢索 |
立即檢索 (除Session的load()預設延遲檢索) |
影響Session的load()方法 |
延遲檢索 |
|||
關聯級別 |
立即檢索 |
預設延遲檢索 |
影響所有檢索方法 |
延遲檢索 |
|||
迫切左外連線檢索 |
|||
影響session的load()和get()方法 |
三種檢索策略的執行機制:
檢索策略型別 |
類級別 |
關聯級別 |
立即檢索 |
立即載入 檢索方法指定的物件 |
立即載入與檢索方法指定的物件相關聯的物件 |
延遲檢索 |
延遲載入 檢索方法指定的物件 |
延遲載入與檢索方法指定的物件相關聯的物件 |
迫切左外連線 <class name="User" table="USER" lazy="false"> 檢索 |
不適 User user = session.load(User.class, new Integer(1)); 用 |
通過左外連線載入與檢索方法指定的物件相關聯的物件 |
類級別檢索策略:
立即檢索(載入):對映配置檔案中<class>元素的 lazy 屬性設定為 false。
<class name="User" table="USER" lazy="false">
延遲檢索(載入):對映配置檔案中<class>元素的 lazy 屬性設定為 true。
<class name="User" table="USER" lazy="true">
立即檢索:
立即檢索
Hibernate立即執行 "select* from user where id=1" 。
延遲檢索:
User user = session.get(User.class, new Integer(1));
延遲檢索
建立 User 的代理類例項(代理類是 Hibernate 動態生成的User的擴充套件類);
Hibernate 建立的 User 代理類的例項僅僅初始化了 OID 屬性,其他屬性均為 null;
當程式第一次訪問代理類例項時(比如user.getX()),Hibernate會初始化代理類例項,執行 select 語句;
如果程式訪問 User 的 getId() 方法時,Hibernate並不會初始化代理類例項,因為 id 值已經存在。
類級別的檢索策略只會影響到 Session 的 load() 方法,對 get() 和其它查詢不起作用。
延遲載入對 load() 方法的影響:
如果資料庫中不存在對應的物件不會丟擲異常,只有在呼叫 user.getXX() 時才會拋異常;
代理類例項只能在當前 Session 範圍內初始化;
Hibernate.initialize() 方法可以顯示初始化代理類例項。
關聯級別檢索策略:
Hibernate需要確定以下檢索策略:
User 類級別的檢索策略;
User 一對多關聯的Order物件的檢索策略,User.hbm.xml 中<set>元素 lazy 和 outer-join 屬性。
在對映檔案中用 <set>元素 來配置 一對多 和 多對多 關聯關係。
lazy |
outer-join |
檢索策略 |
flase |
false |
立即檢索策略。 |
false |
true |
迫切左外連線檢索,在配置檔案中如果有多個<set>元素,只允許一個設定 outer-join=true。 |
true |
false Order order = session.get(Order.class, new Integer(1)); |
延遲載入,優先考慮的檢索策略。 |
true |
true |
迫切左外連線檢索。 |
關聯級別檢索策略-多對一
Hibernate需要確定以下檢索策略:
Order 類級別的檢索策略;
Order 多對一關聯的 User 物件檢索策略,Order.hbm.xml 中 <many-to-one>元素 outer-join 屬性和 User.hbm.xml 中<class>元素的 lazy 屬性。
Order order = session.get(Order.class, new Integer(1));
關聯級別檢索策略 - 多對一 和 一對一
在對映檔案中用 <many-to-one>元素 和 <one-to-one>元素 來分別設定多對一和一對一關聯關係。
<many-to-one>元素的 outer-join 屬性:
auto、true、false三種取值。
關聯級別檢索策略 - 多對一
<many-to-one>元素的outer-join屬性值 |
對應one方<class>元素的lazy屬性值 |
檢索many方(Orders)物件時,對關聯的one方(Users)物件的檢索策略 |
auto |
false |
迫切左外連線檢索 |
auto |
true |
延遲檢索 |
true |
true or false |
迫切左外連線檢索 |
false |
false |
立即檢索 |
false |
true |
延遲檢索 |
使用註解配置檢索策略
fetch 引數可以設定為 FetchType.LAZY 或者 FetchType.EAGER。
EAGER:通過 outer join select 直接獲取關聯的物件。
LAZY(預設值):在第一次訪問關聯物件的時候才會觸發相應的 select 操作。