僅以本書
獻給
“諾曼地大空降”[註 1]
片中飾演
101 空降師
戰火兄弟連[註 2]
的
官、士、兵
HBO“Band of Brothers”影集
即片中驍勇善戰的“Easy Company”( E 連)
代序
很高興能看到一本從軟體設計的角度,用深入淺出的方式帶領讀者一窺
Hibernate 奧秘的書誕生,想想 JBoss 在台灣已生根了二年多,雖然使用 JBoss
Hibernate 的人很多,但是一般開發者大約只用到 Hibernate 的三分之一功能而
已,並且有很多的細節是只知其然,而不知其所以然,本書對於新手來說是最好
的入門書籍,它可以讓你從應用與設計的角度來了解 Hibernate 是如何使用的,
對於高手級的人來說,書中有很多的細節是值得你去深入探索及思考的,再加上
作者以不同型態的筆觸來表現他的思維,相信你也可以透過本書感染到他熱情的
一面,並一同見證 Open Source 在台灣的演變史。
Red Hat JBoss 台灣區資深技術顧問 — Simon Chen 02/19/09' 于台灣
目錄
代序 ................................................................................................... iii
本書閱讀的注意事項 ........................................................................... iv
1 初探 Hibernate 1.1 Hibernate?!據說… ....................................................................2
1.2 從簡化 JDBC 實作的角度來看 Hibernate… .....................................3
1.3 從具現“物件導向思維”的角度來看 Hibernate … ..........................5
1.4 主線任務與支線任務 .....................................................................8
2 Hibernate,一個 更好的 JDBC !? 2.1 增刪改查馬步基本功 ...................................................................14
2.2 組態 - Hibernate 的靈魂 ..............................................................19
2.3 Hibernate 對於主鍵生成的火力支援 .............................................24
vi 目錄
2.4 原生 SQL 的查詢 .........................................................................28
2.5 關於組態對應檔的更多細節 .........................................................32
2.5.1 類別組態檔 ....................................................................... 32
2.5.2 系統組態檔 ....................................................................... 34
2.6 題外話 – Value Object 不等同於領域物件 ...................................37
3 把軟體做軟—淺談物件導向思維‧分析樣式∕設計樣式‧領域
模型 3.1 物件導向基本概念 .......................................................................40
3.2 OOAD ........................................................................................43
3.3 分析樣式 ....................................................................................43
3.4 設計樣式 ....................................................................................50
3.5 平台面的落實..............................................................................60
3.6 從“Think in Data”到“Think in Object” ..................................64
4 開啟物件和關聯式資料庫的一扇門-靜態結構面的對治之道 4.1 個體型別(Entity Type)與值型別(Value Type)........................68
4.2 個體型別(Entity Type)的一對多 ...............................................70
4.3 個體型別(Entity Type)的多對多 ...............................................84
4.4 個體型別(Entity Type)的一對一 ...............................................94
4.5 值型別(Value Type)的一對多...................................................98
4.6 排序處理(Value Type) ........................................................... 105
4.7 值型別(Value Type)的 Component ........................................ 108
4.8 為仲介 Table 加入額外的資訊 .................................................... 114
4.9 繼承 ......................................................................................... 119
4.10 關於複合鍵的對應(mapping)議題 ........................................ 134
5 開啟物件和關聯式資料庫的一扇門一動態行為面的對治之道 5.1 物件的生命週期 ........................................................................ 142
5.2 永續環境(Persistent Context) ................................................ 148
5.3 Detached 物件的識別(identity∕equality) .............................. 155
目錄 vii
5.4 運用 detached 物件的議題 ........................................................ 160
5.5 進一步掌控永續環境(Persistent Context) ............................... 169
6 交易 ! 交易 !! 交易 !!! 6.1 交易三兩事 ............................................................................... 178
6.2 理論的實踐 — 當 Hibernate 碰上交易 ........................................ 190
7 更有效率地運用 Hibernate 7.1 讓您的永續機制產生連鎖效應(Transitive Persistence) ............ 204
7.2 大量資料的處理- Bulk & Batch .................................................. 214
7.3 懶人哲學 v.s. 預先載入 ............................................................. 218
7.4 關於快取 .................................................................................. 240
7.5 單發?三發點放?全自動? …… 回歸原始 SQL 的調校 ............... 252
8 Hibernate 的兩把查詢利器-HQL & Criteria API 8.1 HQL ......................................................................................... 259
8.1.1 基本功 ............................................................................ 259
8.1.2 參數綁定......................................................................... 263
8.1.3 查詢條件......................................................................... 265
8.1.4 Join ................................................................................ 268
8.1.5 HQL 的預先載入 .............................................................. 272
8.1.6 Group By … Having........................................................ 275
8.1.7 子查詢(Subquery)關聯子查詢(Correlated Subquery)276
8.2 Criteria API .............................................................................. 278
8.2.1 基本功 ............................................................................ 278
8.2.2 Join 與預先載入 .............................................................. 283
8.2.3 子查詢 ............................................................................ 287
8.2.4 “轉換器”(Transformer) ............................................. 288
8.2.5 Aggregation & Grouping ................................................. 292
8.2.6 多重查詢......................................................................... 293
8.3 更多 HQL 與 Criteria API 的進階技巧.......................................... 295
viii 目錄
9 術學補遺—更多的 Hibernate 應用 9.1 過濾器(Filter) ....................................................................... 302
9.2 不尋常的 Mapping .................................................................... 307
9.2.1 Formula 的應用 .............................................................. 307
9.2.2 將兩個 Table 對應到一個類別 .......................................... 312
9.2.3 Join Table 的再應用 ........................................................ 313
9.3 Conversation............................................................................ 314
9.4 運用 Hibernate 的 Type System 實作 Martin Fowler 的 Quantity 分析樣式 .................................................................................. 320
9.5 觸發器(trigger)的後遺症 ....................................................... 331
9.6 攔截 Hibernate(Interception) ................................................ 333
9.7 動態模型(Dynamic Model) .................................................... 336
9.8 Blob、Clob .............................................................................. 338
9.9 SQL 生成客製化、呼叫預儲程序(stored procedure) ............... 340
10 實戰演練 10.1 1944/6/6 ( D-day )‧奧馬哈灘頭 .............................................. 344
10.2 實作 Hibernate 基礎建設(infrastructure) .............................. 345
10.3 Spring Framework 諾曼第大空降 ............................................. 356
11 前進 Annotation 11.1 基本功 .................................................................................... 389
11.2 結構的對應 ............................................................................. 397
11.3 其他 ....................................................................................... 408
附錄 A 關於書附光碟的使用 ...............................................415
附錄 B 讓 Hibernate 動起來 ...............................................419
附錄 C Hibernate 的輔助開發工具 ......................................423
附錄 D JUnit .....................................................................437
目錄 ix
附錄 E DBUnit ..................................................................441
附錄 F Hibernate 的數據收集 .............................................445
附錄 G 參考資料 ...............................................................449
初探 Hibernate
本章節涵蓋:
1.1 Hibernate?!據說⋯
1.2 從簡化 JDBC實作的角度來看 Hibernate⋯
1.3 從具現“物件導向思維”的角度來看
Hibernate ⋯
1.4 主線任務與支線任務
2 第 1 章 初探 Hibernate
1.1 Hibernate?!據說…
Hibernate!何方神聖?
據說,連續贏得 2003、2004 Jolt 大獎的 Hibernate,係 Java 社群公認為
永續層(Persistence Layer)框架(Framework)的第一把交椅…是的,在中
原板蕩,群雄四起(JDBC、EJB2.X、JDO、iBatis、TopLink…)的爪哇(Java)
國度裡,快速崛起的 Hibernate,挾其優越的戰力,確實打出了一片江山;事
實上,儼然成為實際(defacto)標準的 Hibernate,更進而深遠地影響 Sun
的官方技術─EJB3∕JPA(Java Persistence API)的發展及制定…
據說,在克服些許的學習曲線後,運用 Hibernate API,可大幅簡化使用
“純”JDBC 所撰寫的繁瑣程式碼…相信曾歷經 Hibernate 洗禮的程式設計
師,大多能夠認同:Hibernate 確實能相當程度地提升產能!(我們將在下一
節,約略比較兩者的寫法)
據說,在當年 OO(物件導向)躍上舞台之際,以及伴隨而來的 UML
(Unified Modeling Language)、方法論如 UP(Unified Process)、Analysis
Patterns(分析樣式)、Design Pattern(設計樣式)…等,當人們試圖透過
這些傳說中的銀色子彈來打造更美好的軟體美麗新世界時…,無奈,一旦當物
件遇上了資料庫,腦中的 OO 設計,好一部分難以在實務中具現,於是乎,教
本上的 OO 設計思維,幾乎成了海市蜃樓,夢幻泡影;以商務系統為例,商業
邏輯層(Business Layer)中最為核心的領域物件(這裡指的領域物件不是光
只有 getXXX 和 setXXX 的“資料”物件 [註 ]),碰到資料庫就掛點了…畢竟,
領域物件(Domain Object)和資料庫的 Table 不全然是一對一的對應,邏輯
上的 O∕R Mapping(即領域物件和資料庫 Table 之間的對應)有規則可尋,
而實作上的轉換(將 Table 中的資料取出,並轉換成記憶體中的物件,或將記
憶體中的物件儲存至資料庫中),若考慮到框架( framework)的完備性,則
非易事…而 Hibernate,正是 ORM(O∕R Mapping Mechanism)的翹楚!
意即我們一般常看到只有存取屬性 method 的 Value Object。
1.2 從簡化 JDBC 實作的角度來看 Hibernate… 3
1.2 從簡化 JDBC 實作的角度來看 Hibernate…
行之有年的 JDBC,係 Java 國度中一統資料庫存取的制式 API,儘管 JDBC
勞苦功高,但仍有改善的空間:
1. JDBC 標準化了資料庫的存取方式,然各家資料庫的 SQL 仍有所差
異,JDBC 並未統一 SQL 的寫法;如果您要實作一套適用多種不同品
牌資料庫的套裝軟體,使用 JDBC,恐怕還是難逃撰寫多套 SQL 的厄
運…。
2. 我們在上一節約略提到在商業邏輯層具現物件導向思維的難處(我們
將再下節進一步來探討此議題),是的,JDBC 從資料庫撈出的是
ResultSet,而非領域物件 —— 我們不該苛責 JDBC,畢竟她本來就
是比較貼近資料面的處理, JDBC 在本質上就不是 ORM( O∕ R
Mapping Mechanism)框架!
3. 使用純 JDBC 撰寫的程式碼很是繁瑣,咱們緊接著就來看看:同為新
增資料的等價功能,分別用 JDBC、Hibernate 以及 Hibernate 搭配
Spring 來實作是什麼樣的光景(請您先將焦點放在程式碼的行數上,
暫時先別太在意程式的內容):
表 1-1 比較 JDBC∕Hibernate∕Hibernate + Spring 的實作
使用 JDBC 實作
Public void saveMember(Member member) throws SQLException{ … try { conn= dataSource.getConnection(); stmt = conn.prepareStatement("insert into Member " + " (FirstName, LastName, … … … … … … CreateTime )" + " values (?, ?, ?, … … … … … … … … … … … ?) "); stmt.setInt(0[註], member.getId().intValue()); stmt.setString(1, member.getFirstName()); stmt.setString(2,member.getLastName()); … //一個蘿蔔一個坑 … //紅蘿蔔蹲完黃蘿蔔蹲 … //黃蘿蔔蹲完綠蘿蔔蹲
4 第 1 章 初探 Hibernate
… //實在粉累人說 … stmt.setString(99,member.getCreateTime()); stmt.executeUpdate(); } catch(SQLException e) { … } finally { … } // ORZ …
使用 Hibernate 實作
public void saveMember(Member member) … Session session = HibernateHelper.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); session.save(member); tx.commit(); session.close(); // 哇喔!清爽多了
使用 Hibernate 搭配“Spring Framework”
public void saveMember(Member member) … getHibernateTemplate().save(member); … } //喔后后 … 這下變得超簡潔的說 … //我們將在第十章提及 Hibernate 與 Spring 的整合。
改成這樣會稍稍好些(至少不用在欄位有所增減時,調序號調掉半條命 …)
int i = -1; stmt.setInt(i++, member.getId()); stmt.setString(i++, member.getFirstName()); stmt.setString(i++, member.getLastName());
哇喔!光是程式行數明顯的差距,就讓人對 Hibernate 感到相當的興趣
了!再稍微領略兩者的寫法後,我們可以發現,從資源管理( Resource
1.3 從具現“物件導向思維”的角度來看 Hibernate … 5
Management)、例外處理(Exception Handling)、交易(Transaction)、
下 SQL 的角度來看,Hibernate 的寫法都簡便了許多…而 Spring 則讓 Hibernate
更加如虎添翼!如果您未曾接觸過 Hibernate,相信您已經開始心動了喔…。
而針對方才提到 JDBC 不足之處,Hibernate 的作為是:
1. 將 JDBC 進一步封裝的 Hibernate,在 SQL 的可攜性上所做的努力,
是有目共睹的。
2. 對於種種 O∕R Mapping 的疑難雜症(不管是靜態結構面,還是動態
行為面),Hibernate 基本上都可以迎刃而解。
3. Hibernate 在程式碼的簡化上,絕對是不遺餘力的,表 1-1 所做的比較,
只是冰山的一小角!
我們將在後續的章節,逐步揭露 Hibernate 強大的功能。
1.3 從具現“物件導向思維”的角度來看 Hibernate …
猶記得當年 UML∕UP 開始風行時,多少人將之視為救命仙丹;但在實作
見公婆時,我們發現在商業邏輯層要能按“圖”施工[註 ],確實有其困難度…。
畢竟,從結構與行為來看物件和資料庫,兩者是不全然相同的世界…。
我們來看看兩種常見的施工藍圖,底下是一張典型的 Class Diagram:
喔,請別誤會,筆者並非 UML 的死忠擁護者,有沒有真的具足 OO Thinking,
遠比會不會畫 UML 圖重要多了。
6 第 1 章 初探 Hibernate
圖 1-1 類別圖(Class Diagram)
以上圖的繼承來說吧,該如何將物件對應到資料庫的 Table 呢?顯然將物
件和 Table 直接做一對一的對應(解法有三種,請參閱第四章),並非一定是
最佳解,而當兩個物件為 1-1 的關係時,在資料庫的設計上,基於效能的考量,
往往是將兩個物件收編到同一 Table 裡,還有多對多的 Class Diagram 和 E-R
Diagram 的結構不應該會是完全相同…凡此種種結構上的差異,都是需要克服
的問題。
領域物件和資料庫的 Table 並非全然是一對一的對應!Hibernate 協助我
們解決兩者在結構上的不對盤,並相當程度地做到:改資料庫的 Schema,並
不影響既有的程式碼。
1.3 從具現“物件導向思維”的角度來看 Hibernate … 7
再來看看 Sequence Diagram:
圖 1-2 循序圖(Sequence Diagram)
我們觀察,幾乎所有 OO 教本上的塑模(Modeling),其假設點似乎是預
設所有的 Table 都已轉化為物件,並快取(cache)在記憶體內了,而且忽略
掉存取資料的動作(或許我們可以換個角度思考:是不是可以真的不要去寫存
取資料的程式碼),這是不切實際的,而在實務上,一次該擷取多少資料到記
憶體內(並轉換成對應的物件結構),亦是一大難題!
而 Hibernate 自動產生 SQL,並將 Proxy 設計樣式發揮到淋漓盡致的解
法,某種程度克服掉這種物件導向與資料庫在行為上的差異!
但話說回來,UML 是表情達意的工具(Notation),而軟體開發方法論
(methodology)重量級如 RUP,輕量級如 eXtreme Programming 恐怕也不
是照單全收(應該因人因時因地因專案體質加以裁適運用)就是軟體成功的保
證,而人才是把軟體做軟的主角,具足形而上的物件導向思維,搭配優質的
ORM 框架,才能讓 OOAD(Object-Oriented Analysis & Design;物件導向分
析與設計)真的發揮作用;(我們將另闢一章“第三章 把軟體做軟 — 淺談
物件導向思維‧分析樣式∕設計樣式‧領域模型”來談談 OOAD),心法(OO
8 第 1 章 初探 Hibernate
思維)尤甚於器(ORM 框架) — ORM 如 Hibernate,不過是具現物件導向
思維的手段罷了呀!
1.4 主線任務與支線任務
筆者分別用逐章導讀和任務編組的方式,來綜覽本書的架構。各章簡介如
下:
第 1 章 初探 Hibernate
點出 Hibernate ORM 框架如何大幅改進 JDBC,並揭櫫心法(OO 思維)與功法
(Hibernate How To)兼修,在最核心的商業邏輯層(領域模型)落實物件導向的
精神,發揮軟體的“軟”性。
第 2 章 Hibernate,一個更好的 JDBC!?
本章其實是從比較資料面(Think in Data)的角度來看 Hibernate,主要是想藉由您
所熟悉的 JDBC 來入手(增、刪、改、查 … 還有其他如序號 … 等等等議題);
一探 Hibernate 如何簡化用“純 JDBC”寫的程式碼,以及 Hibernate 如何提高 SQL
的可攜性。
第 3 章 把軟體做軟─淺談物件導向思維‧分析樣式∕設計樣式‧領域模型
縱然本書主要還是著眼於 Hibernte 的 How to,但筆者只是想再次強調本書的題旨:
Hibernate 3.x — 具現物件導向思維的好幫手 …… 聰明如您,大概只消一晚就可以
入手 Hibernate 了,但物件導向思維,對於普羅大眾而言;要能從皮,到骨,甚至
深入到髓,恐怕是需要一些時日的修練和精進。而想用一個章節的篇幅來深入淺出
“物件導向”這麼大的題目是不可能的任務,但如果您是物件導向的初學者,筆者
還是想試著野人獻曝,提供一個修習 OO 的指引。如果將全書比作一首詩,那麼本
章應該是這首詩的“詩眼”了。
第 4 章 開啟物件和關聯式資料庫的一扇門 – 靜態結構面的對治之道
前文已提及:領域物件和資料庫的表格,應該不會全然是 1—1 的對應;畢竟資料庫
要考慮到效能和資料量等因素;因此 E-R 的設計會有收編整併、正規劃∕反正規劃
(normalization∕denormalization)的考量(因而導致語意的失真),而兩者在結
構上的差異,Hibernate 算是鞠躬盡瘁地幫我們服務到家了。
接續下頁
1.4 主線任務與支線任務 9
第 5 章 開啟物件和關聯式資料庫的一扇門 – 動態行為面的對治之道
本章除了從動態行為面探討 OO 和資料庫的差異以及 Hibernate 的對治之道,並深
入了解 Hibernate 歩的運作原理,以利更近一 掌控 Hibernate。
特別是“5.2 永續環境(Persistent Context)”,我們一定要好好地,用力地吸收消
化,才有可能學通 Hibernate。
第 6 章 交易!交易!!交易!!!
像交易這般超重要的課題,我們當然要另闢一章來好好地談一談,本章論及樂觀鎖
定(版本控管)∕悲觀鎖定…等與交易相關的議題。
第 7 章 更有效率地運用 Hibernate
本章從效能,記憶體用量,程式碼的簡化等角度,乘勝追擊 Hibernate 的進階使用。
第 8 章 Hibernate 的兩把查詢利器 - HQL & Criteria API
查詢是重頭戲,因此特闢一章來將 Hibernate 的查詢細說從頭。
第 9 章 述學補遺 — 更多的 Hibernate 應用
所有其他難以歸類,或是比較另類,更為進階的議題和用法,皆集中於本章。
第 10 章 實戰演練
本章論及輕量級 Java EE 的架構和 Hibernate∕Spring∕Struts 的整合。
第 11 章 前進 Annotation
Annotation 已是大勢所趨,本章介紹 Hibernate Annotation(含 JPA 和部分 Hibernate
自家的 Annotation)的用法。
如果將閱讀本書比作角色扮演遊戲(RPG;顯然筆者此刻正迷失在龍與地
下城,被遺忘的國度裡),那麼主線任務應該是:了解如何運用 Hibernate 實
現物件導向思維。
而其他大大小小的支線任務,則略為說明如下:(建議您略為取得一個印
象即可,日後視需要再來回顧本節)
10 第 1 章 初探 Hibernate
關於“程式碼的簡化”(相較於 JDBC)
基本上,建議您閱讀完每一個段落,都能想想書中的範例,如何用“純”JDBC 來
實做,兩相比較,對於 Hibernate 的做法,印象應該能更為深刻。
關於“減震點”
更改 Database Schema,能夠儘量不要更動到程式碼,是多麼令人 Happy 的事;
Hibernate 的組態檔即扮演了這麼一個“減震點”(或“防火牆”)的角色。您將在
全書看到 Hibernate 貼心的表現。
關於“提升 SQL 的可攜性”
散見於第 2 章、第 4 章、第 5 章、第 6 章、第 7 章、第 8 章、第 9 章、第 11 章。
記憶體用量
Hibernate 操控不慎,可能會導致記憶體用量暴增(甚至爆掉),“5.5 進一步掌
控永續環境(Persistent Context)”特別談及如何針對記憶體節衣縮食。其他還包
括“ 7.2 大量資料的處理 - Bulk & Batch ”、 8.3 一節的“游標卷軸”和
“org.hibernate.readOnly”等內容,都是您應該要特別關心的。
Hibernate 的頭號大陷阱:LazyInitializationException
Hibernate 的懶人哲學著時帶來很大很大的便利,但稍有不慎,很容易引爆
LazyInitializationException 地雷。杜絕之路不只一條,請參考“7.3 懶人哲學 v.s. 預
先載入”,以及“10.2 實作 Hibernate 基礎建設( infrastructure)”、“10.3 Spring
Framework 諾曼第大空降”兩節的 Open Session In View。
Hibernate 的懶人哲學還影響到 HQL 和 Criteria API,請參考“8.1.5 HQL 的預先
載入”和“8.2.2 Join 與預先載入”。
“N + 1 Select”問題,對於初學 Hibernate 的人來說,可能也是一個不小的困擾,
本書在“7.3 懶人哲學 V.S. 預先載入”,以及“8.1.5 HQL 的預先載入”、“8.2.2
Join 與預先載入”都有著墨。
關於“Hibernate 運作原理”
請特別留意第 5 章、第 7 章。
關於“效能”
第 5 章和第 7 章。
接續下頁
1.4 主線任務與支線任務 11
關於“組態定義”
關於“開發輔助工具”(Hibernate Tool)
我們將於附錄 C 中,以看圖說故事的方式,來說明 Hibernate“開發輔助工具”的
使用;Hibernate 大幅簡化存取資料庫的程式碼,而“Hibernate Tool”協助您更輕
易地操控 Hibernate 框架。
關於“測試”
“ Programmer Test ” 不 是 什 麼 新 鮮 事 兒 , 但 近 年 在 國 外 風 行 的 eXtreme
Programming 之推波助瀾下,儼然成為一門顯學;我們將在附錄略為提及兩個代表
性的工具:JUnit 及 DBUnit。
關於“物件導向思維”
除了第 3 章,在第 10 章(特別是章末),我們都還有針對“OO 思維”加以著墨。
關於“資料庫查詢”
請見“2.4 原生 SQL 的查詢”及第 8 章。