1、對象關係映射
1-1、單向多對一關聯
產品和分類的關係:多個不同產品屬於同一種分類。
private Category category;
<many-to-one name="category" column="categoryId" not-null="true" />
1-2、一對多映射
private Set products = new HashSet();
<set name="products" <!--Category 中集合屬性名稱為 products-->
table="product" <!--集合屬性對應表的名稱為 product-->
schema="test" <!--表的 schema 名稱為 test-->
lazy="true" <!--此集合採用延時載入策略-->
inverse="true" <!--由關聯屬性的另一方作為關聯的主控方-->
cascade="delete" <!--採用串聯刪除,當 Category 被刪除時關聯的此集合內容也將被刪除-->
sort="natural" <!--自然排序集合內容-->
order-by="productId asc" <!--按 productId 欄位升序排列集合內容-->
>
<key column="category_fk" />
<one-to-many class="petstore.domain.Product" />
</set>
1-3、繼承映射
2、Hibernate 操作對象
2-1、對象的三種狀態
● 瞬時態(Transient)--VO(Value Ojbect)
對象執行個體產生到被 JVM 記憶體回收為止並不受 Hibernate 架構管理。
● 持久態(Persistent)--PO(Persistent Ojbect)
對象執行個體被 Hibernate 架構管理,該對象可能是剛被儲存的,或剛從資料庫中被載入的。Hibernate 會檢測處於持久態的對象任何改動,在當前操作單元執行完畢將對象與資料庫同步,即將對象的屬性儲存到資料庫映射對應的欄位中。簡單點說就是該實體物件與 session 發生關係,而且處於 session 的有效期間內。
● 託管態(Detached)--VO(Value Ojbect)
與持久對象關聯的 Session 被關閉後,對象就變為託管的,可繼續被修改。託管對象如果重新關聯到某個新的 Session 上,會再次變為持久的,同時改動也將會被持久化到資料庫。這個期間的轉變過程可以看作是應用程式事務,即中間會給使用者考慮時間的長時間啟動並執行操作單元。
處於託管態對象具有與資料庫表記錄間的聯絡(持久化標識,identifier)。
2-2、對象操作的應用程式介面
● 修改對象
對於已經持久化的對象,不需要調用某個特定的方法就可以實現修改持久化,因為 Hibernate 會自動調用 flush() 方法保證與資料庫的同步。
對於處於託管狀態的執行個體,Hibernate 通過提供 Session.update() 或 Session.merge() 方法,重新關聯受管理的執行個體。但是需要注意的是:如果具有持久化標識(identifier)的對象之前已經被另一個會話串連(secondSession)裝載了,應用程式關聯操作會發生異常。
使用 merge() 方法時,使用者不必考慮 session 的狀態,可隨時將修改儲存到資料庫中。例如:Session 中存在相同標識的持久化執行個體時,Hibernate 便會根據使用者給出的對象狀態覆蓋原有的持久化執行個體的狀態。
另外,Hibernate 還提供了 saveOrUpdate()方法,它即可分配新持久化標識(identifier),儲存瞬時(transient)對象,又可更新/重新關聯託管的(identifier)執行個體。
● 刪除對象
通過 HQL 語句,調用重載的 delete(),可以一次刪除多個對象。
session.delete("from Customer as c where c.customerId <3");
● 查詢對象
已知對象表示符值查詢
物件識別碼未知查詢 HQL
根據某些特定條件查詢 QBC,Query By Criteria
按詳例查詢 QBE,Query By Example
調用資料庫查詢 native SQL
查詢條件參數 ? 查詢條件參數索引,由 0 開始。
查詢條件實名 :name
外置命名查詢
在對應檔定義查詢語句,將程式與查詢語句分離:
<query name="CategoryById"
<! [CDATA[
from Category c where c.categoryId>? ]]>
</query>
程式調用:
Query q = sess.getNamedQuery("CategoryById");
q.setLong(0, name);
List cats = q.List();
用 Query 提供的 iterate() 方法遍曆查詢結果,如果查詢的結果在 session 或二級緩衝(second-level cache)中,那麼使用 iterate() 方法可以得到更好的效能。
如果 JDBC 驅動支援可滾動的 ResuleSet,Query 介面可以使用 ScrollableResults,允許你在查詢結果中靈活移動(需要保持資料庫連接和遊標 cursor 處於抑制開啟狀態)。
ScrollableResults cates = q.scroll();
cates.first()
cates.scroll(5);
● cascade 和 inverse 級聯操作
inverse
只對 set,one-to-many(或 many-to-many)有效,對於 many-to-one,one-to-one 無效
對集合起整體作用
cascade
對關係標記都有效
對集合的一個元素起作用,如果集合為空白,那麼 cascade 不會引發關聯操作
作用時機:在 flush 時(commit 會自動執行 flush),hibernate 會自行判斷每個 set 是否有變化,對有變化的 set 執行相應的 SQL,if (inverse) return。即:cascade 在前,inverse 在後。
異常:
org.hibernate.exception.ConstraintViolationException: could not insert
原因是 category_fk 欄位約束不可為空,而在建立的 Product 對象時插入了空值,而且關聯關係由 Caterogy 對象維持,而被關聯的 Product 對象不知道自己與哪個 Category 對象關聯。說到底就是 pro 對象的 categoryId 值為空白。